Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Bombay Behavior

Bombay Behavior provides a pure, statically typed actor transition algebra and a catalogue of reusable actors. A behavior processes one communication at a time and returns explicit Actions: typed communications, staged fresh actor creations, and its next behavior or termination decision. Scheduling, transport, clocks, allocation, and effect execution remain interpreter responsibilities.

This guide has three documentation classes:

  • Canonical contracts describe the current behavior algebra, application authoring syntax, composition laws, and interpreter obligations.
  • Actor catalogue documents the current reusable atomic actors and their normalized aggregate laws.
  • Engineering records preserve research, rejected alternatives, audit evidence, and implementation campaign decisions. They explain why the current design exists but are not an additional public API contract.

The generated API references are published alongside this guide:

When a historical engineering record conflicts with the crate API or a canonical contract, the current public types and canonical contract govern.

Actor transition algebra

This is the canonical semantic map for Bombay Behavior.

Laws and project constructions

The actor-model laws preserved here are:

  1. an actor processes one accepted communication at a time;
  2. a transition may communicate with known recipients, create fresh actors, and designate the behavior used for the next communication; and
  3. a newly allocated actor address is fresh with respect to the actor configuration.

Bombay derives a concrete typed construction from those laws:

Behavior::transition(ActiveTurn, Behavior::Event)
    -> Result<Actions<Addr, Phase, Sends, Birth>, Error>

Actions is the only effect boundary. Typed send products, closed creation products, initialization effects, phases, explicit termination, structural event paths, creator-local child routing, and interpretation order are Bombay constructions and policies, not claims about the surface syntax of Agha's formal calculus.

Four orthogonal roles

RoleOwns
Protocolcanonical destination identity, address namespace, message type
Behavior::Eventevery public and interpreter-originated event accepted by a concrete behavior
Behaviorstate, initialization, and the pure event fold
Actionsall communications, staged fresh creations, and the next-state verdict

A protocol is not a behavior. It has no state, initialization, internal event lanes, effects, errors, phases, or birth capabilities. A behavior is not a protocol supertrait: senders need only the destination's public signature, not proof of its current implementation.

A nominal actor may implement both traits and use Behavior::Protocol = Self. Transparent wrappers preserve the inner protocol while changing the concrete behavior and event/effect algebra.

InitializationTurn and ActiveTurn cannot be constructed directly by an application. The public initialize(&mut B) and delegate_transition(&mut B, event) functions are trusted composition and runtime ports: they can be called repeatedly, and the latter can run before initialization. The consuming behavior_actors::Activate::initialize path enforces one initialization for its owned definition and returns Active<B> for mailbox ingress. A runtime or wrapper using the raw ports must enforce the same lifecycle order itself.

Destination evidence

TypeEvidenceRequires address lookup?
Recipient<P>logical address with canonical protocol Pyes
Delivery<P>logical recipient plus P::Msgyes
ChildDelivery<P, O>message to a committed local occurrence/nonce bindingno protocol-wide lookup
EstablishedRecipient<P>exact installed endpoint for Pno
EstablishedDelivery<P>exact endpoint plus P::Msgno
EstablishedActor<B>exact installed B endpoint and matching lifecycle authorityno

P is always canonical protocol identity. O is structural occurrence evidence used to navigate duplicate child declarations. It is not a key, address, or second identity.

The runtime selects exact message endpoints through RecipientAddress::Established<P>. Actor-hosting namespaces additionally select EndpointAddress::Installed<B>, which projects the endpoint and keeps matching B::Event authority. Generic application types and protocol owners do not implement key traits or carry runtime types. The inert endpoint family requires Clone, not Send. InterpretSends and concrete request interpretation require Send when an effect actually crosses an asynchronous executor boundary.

Fresh creation

CreateChild<A, C> stages a concrete child behavior, creator-local nonce, and CreationKind. Staging allocates nothing. The nonce cannot be converted to an address and proves neither identity nor freshness.

The interpreter performs, in order:

  1. reserve an address fresh with respect to the actor configuration, without publishing a live endpoint;
  2. run the child's pure definition initialization fold;
  3. install the endpoint and commit the creator-local nonce binding;
  4. interpret and settle all initialization effects; and
  5. permit ordinary mailbox ingress only if initialization continues and its effects settle successfully.

Only the committed path may produce ChildCreationOutcome<C, Occurrence>::Established(CommittedChild<C, Occurrence>). A later named report may return EstablishedCreation<C, Occurrence>::Installed with the same committed product. Allocation rejection returns the complete staged creation before the initialization fold. Pure initialization rejection returns the current child and exact error; host rejection after that fold returns the current child and uninterpreted initialization Actions. A caught pure initialization panic returns the extant current child through InitializationPanicked, without claiming an initialization error or accepted actions. None of these outcomes commits a binding. Once committed, an initialization-effect failure belongs to the installed child's drain and cannot be reported as a creation rejection. An initialization Stop still settles its final actions and never enables ordinary ingress. A nonce collision is rejection, never replacement or overwrite.

These commit and settlement steps are Bombay policy, not Agha's allocation law. Agha et al.'s newadr and initbeh are separate model operations; Bombay packages fresh allocation, the pure fold, and establishment into one staged creation request.

CreationKind::ReplacementIncarnation records Behavior-authored provenance. It is still fresh allocation. A runtime may report a restart only after the corresponding replacement creation commits successfully.

Creation facts are indexed by canonical child protocol and structural occurrence—not by an entire parent behavior. A fact can be strengthened to EstablishedActor<RoleChild<Parent, Occurrence>> only at the topology boundary where ChildRole<Parent> genuinely proves the concrete installed behavior. This avoids forcing arbitrary consumers or wrappers to pretend to be actors.

Event and effect composition

EventLayer<Owned, Inner> forms a closed event sum. Here identifies the current owner and Inside<Path> identifies an inner owner. InjectEvent constructs exactly the selected lane; it never searches by payload type.

SendLayer<Owned, Inner> is the corresponding named effect product. SendsFor<Event> proves that every interpreter request returning to its emitter has a valid structural ingress. InterpretSends visits inner effects before wrapper-owned effects, preserving initialization and delegated transition order. Independent named lanes retain their own order; no global order is invented between unrelated lanes.

Composition must preserve these invariants:

  • every accepted event produces one result;
  • mapping sends preserves creations and the exact next verdict;
  • mapping the next verdict preserves sends and creation order;
  • wrapping cannot drop, duplicate, reinterpret, or consume an inner lane;
  • duplicate structural occurrences remain distinct;
  • established, child, and external destinations are not reindexed merely because the emitting behavior is wrapped; and
  • controlled failure emits no partial effects.

Static interpretation

ActionItem fixes the outcome vocabulary of each emitted value. SendSettlements fixes the complete product shape independently of any runtime. InterpretItem and InterpretSends are the monomorphized runtime capabilities. Closed child sums use DispatchBirth and one EstablishChild<Occurrence, Child> implementation per concrete occurrence. Missing support fails to compile.

ChildOccurrenceProduct is the structural product needed by runtimes that retain creator-local state per direct child occurrence. Behavior owns the closed Behavior leaf / ChildChoice / Never recursion and supplies the same ChildHead / ChildTail<_> navigation evidence used by child creation. A runtime-owned ChildOccurrenceShape supplies only the storage constructor. This is a type-level derived construction, not an actor operation: it performs no transition, allocation, binding, lookup, or effect interpretation. Transitive descendants remain owned by the concrete child actors that may create them.

ResolveChildOccurrence<O> supplies the inverse static connection needed when an effect names O: the running emitter and occurrence determine one exact direct child behavior and structural position. Generated nominal roles are resolved through BehaviorBase only while protocol and birth topology remain identical; raw ChildHead/ChildTail<_> positions inspect the emitter's own closed birth node. Consequently a supervision wrapper that replaces a direct child with a proxy cannot silently reinterpret the base role. This is navigation evidence derived from Behavior, not a new identity or effect.

No core path uses trait objects, runtime protocol registries, reflection, downcasting, type-name dispatch, serialization, or unsafe type escape hatches.

Code map

  • crates/behavior/src/transition.rs: protocol and behavior contracts
  • crates/behavior/src/effects/: actions and static send interpretation
  • crates/behavior/src/actor/addressing.rs: logical and established recipients
  • crates/behavior/src/actor/creation.rs: staged creation and structural dispatch
  • crates/actors/src/protocol/established.rs: exact creation, observation, and shutdown protocols
  • crates/actors/src/requirements.rs: occurrence-preserving installation requirements

Bombay Behavior core type inventory

Scope

This document inventories the types exported at the root of the bombay-behavior crate (behavior in Rust source). The authority for the list is crates/behavior/src/lib.rs; semantic descriptions are taken from the defining modules in crates/behavior/src. It describes the current source surface, not a proposed redesign.

The inventory includes public traits, structs, enums, and type aliases. It also identifies the crate's public functions and #[behavior] macro because they construct or consume the types. It excludes private module items, test-only fixtures, and downstream types generated in a user's crate except for a separate description of the macro-generated family.

Some root exports are marked #[doc(hidden)]. They remain listed because they are publicly nameable implementation contracts, but ordinary behavior authors should not treat them as the preferred API.

Semantic center

The central relationship is:

Protocol = address namespace × public message type

Behavior = protocol
         × complete event algebra
         × send product
         × birth algebra
         × phase menu
         × controlled error

BehaviorActed<B>
    = Result<
          Actions<BehaviorAddr<B>, B::Ph, B::Sends, B::Birth>,
          B::Error,
      >

Actions = sends
        × ordered staged fresh creations
        × (Continue | Goto(phase) | Stop(Stopped))

Protocol is stable public communication identity. Behavior is the concrete stateful fold implementing that protocol. They are deliberately separate: recipients and deliveries do not recursively carry a destination behavior's sends, births, phases, or errors.

Actions is Bombay's typed realization of actor-transition effects. It is not described as a literal Agha effect triple: the Rust surface additionally owns typed send products, creator-local child routing, phases, controlled errors, termination, initialization effects, and Bombay interpretation ordering.

Protocol, behavior, and transition types

TypeKindSemantic role
ProtocolTraitAssociates one stable public actor identity with Addr: Address and Msg. It is independent of transition implementation.
MessageProtocol<A, M>Zero-state structReusable nominal-free protocol signature for address type A and message type M.
BehaviorTraitPure initialized fold from one complete typed event to BehaviorActed<Self>. Associated types expose protocol, event, sends, phases, controlled error, and birth capability.
BehaviorActed<B>Type aliasExact controlled result type of behavior B: Acted<BehaviorAddr<B>, B::Ph, B::Sends, B::Birth, B::Error>.
BehaviorAddr<B>Type aliasProjects the address namespace from B::Protocol.
BehaviorMessage<B>Type aliasProjects the public message type from B::Protocol.
InitializationTurnNon-constructible structPrevents direct caller fabrication; trusted public composition ports can issue it repeatedly, while the consuming Activate path enforces one initialization for its owned definition.
ActiveTurnNon-constructible structLifecycle- or composition-issued authority to invoke one active transition.
BehaviorLayer<B>TraitStatically constructs one fully concrete behavior from another; closures implement it without trait objects or effects.
BehaviorBaseTraitProjects a composed wrapper to its authored base behavior without exposing wrapper depth.
LogicalHostRequirementsTraitDerives the ordered, duplicate-preserving logical protocol hosts required by a behavior's sends and transitive births. It is static evidence, not allocation.

The associated type equation of Behavior is:

Behavior {
    Protocol: Protocol
    Event: UserEvent<Addr = BehaviorAddr<Self>,
                     Message = BehaviorMessage<Self>>
    Sends: SendEffects + SendsFor<Event>
    Ph
    Error
    Birth: BirthMode
}

Next-state and action types

TypeKindSemantic role
NeverUninhabited enumProves absence. It is used for no phase transitions, impossible events, and empty closed sums.
StoppedUnit structPayload-free normal behavior-termination marker. Lifecycle provenance belongs in typed protocols, not this seat.
Step<Ph, R>EnumExhaustive next verdict: Continue, Goto(Ph), or Stop(R).
Become<Ph>Type aliasBehavior next verdict, fixed to Step<Ph, Stopped>.
Actions<A, Ph, Sends, Birth>StructExplicit transition product with named sends, ordered creates, and become_ legs. The interpreter commits creations before same-action sends that may depend on them.
Acted<A, Ph, Sends, Birth, E>Type aliasResult<Actions<A, Ph, Sends, Birth>, E>.
AppendSend<Input, Path>TraitAppends one input to a statically selected send lane while preserving creation and next-state legs.

Actions constructors (cont, stop, goto, send, and create) construct values only. They do not interpret sends, allocate actors, change runtime state, or perform lifecycle work.

Addressing and installed-capability types

TypeKindSemantic role
AddressTraitDefines a pure logical address namespace and its creator-local Nonce. A nonce is correlation, not address or freshness proof.
MailAddrNewtype structBuilt-in u64 logical address whose nonce is also u64.
EndpointAddressTraitRuntime-owned projection from a logical address namespace and protocol to an exact endpoint representation.
Recipient<P>StructPure logical destination for protocol P; proves protocol/address/message agreement but not installation.
EstablishedRecipient<P>StructInert runtime-issued capability for one exact installed incarnation of protocol P. Its endpoint is not directly exposed.
InterpretEstablished<P>TraitExplicit power-user boundary that consumes an established recipient's exact endpoint.
EstablishedActor<B>StructExact installed capability that preserves both the public recipient and the concrete installed behavior type B.
Delivery<P>StructPure logical communication containing Recipient<P> and P::Msg.
EstablishedDelivery<P>StructPure communication to one exact EstablishedRecipient<P> without logical-address resolution.

The capability strength increases from logical naming to installed evidence:

Recipient<P>
    logical protocol destination

EstablishedRecipient<P>
    exact installed endpoint for P

EstablishedActor<B>
    exact installed endpoint for B::Protocol
    + static proof of concrete behavior B

None of these values has an ambient send, shutdown, allocation, or lookup method. Effects cross explicit interpreter traits.

Event and ingress types

TypeKindSemantic role
User<A, M>StructBase public user-message event with from: A and message: M.
UserEventTraitConstructs and extracts the public User lane through a complete composed event algebra.
EventLayer<Owned, Inner>EnumConcrete coproduct `Owned(Owned)
ComposedEventTraitIdentifies an event algebra's inner event and its structure-preserving injection.
EventIngress<Source, Input>TraitOwner-selected construction of one input lane without caller-visible wrapper paths.
ChildInputIngress<Source, Input>TraitConstructs a private parent-to-child input in the concrete child's event algebra.
InjectEvent<Input, Path>TraitLow-level path-indexed injection into a structural event coproduct.
Ingress<Input, Path>Zero-state structAddress-free capability selecting one exact interpreter-return ingress member.
HereUnit structCompile-time path selecting the current event or send layer.
Inside<Path>Zero-state structCompile-time path selecting an inner layer.

Here and Inside<Path> are structural proof types, not runtime routing addresses. Ordinary composed templates should prefer semantic EventIngress<Source, Input> implementations so callers do not count wrapper depth.

Send products and interpretation types

Send-product algebra

TypeKindSemantic role
SendEffectsTraitClosed value algebra with empty, ordered append, and statically selected lane emission.
SendsFor<Event>Marker traitProves that a send product's returning interpreter requests are lawful for the exact complete event algebra.
SendInput<Input, Path>TraitSelects one request lane at compile time and emits into it.
OwnUninhabited marker enumSelects a named send product's own semantic lane.
NoSendsUnit structNamed empty send product.
SendLayer<Owned, Inner>StructNamed product of wrapper-owned and inner send effects. Interpretation preserves inner-to-outer authored order.
LogicalDeliveryProtocolsTraitProjects possible logical recipients from a send product while preserving order and duplicates.
InterpreterRequestTraitDeclares a request's emitter continuation and its possible logical recipient protocols.
InterpreterRequests<M>StructOrdered send lane of runtime-local requests with no actor address.
NoReturnToEmitterUninhabited enumDeclares that an interpreter request produces no later local event.
ReturnsToEmitter<Input, Path>Zero-state structDeclares a later local event of Input at a compile-time event path.
ReportToParent<R>StructTransfers an owned report through the established creator/child relationship; the interpreter attaches the exact occurrence-local creation ID.

The crate supplies SendEffects/interpretation implementations for selected Vec<T> lanes, including logical deliveries, established deliveries, creator-local child deliveries and inputs, and Vec<Never>. A general Vec<T> is a send value container, but only statically supported effect kinds receive interpreter meaning.

Interpreter capabilities

TypeKindSemantic role
ActionItemTraitFixes one action item's accepted receipt, rejection, and prerequisite types for every runtime.
ItemSettlement<Item, Accepted, Rejection, Prerequisite>EnumConserves one attempted item across acceptance, rejection, prerequisite blocking, and interpreter corruption.
SettledItem<Item, Settlement>EnumDistinguishes an attempted item from an untouched item after earlier corruption.
Interpretation<Settlement>EnumOwns the complete product after successful traversal or corruption.
SendSettlementsTraitProjects one concrete sends product to its runtime-independent settlement product.
ActionSettlementsTraitProjects one concrete Actions product to its complete creation-and-send settlement.
BehaviorSettlementsTraitBlanket projection from a concrete behavior to that exact action-settlement type without restating internal birth or send bounds.
InterpretItem<Item, RootEvent, Path>TraitLets one concrete runtime attempt exactly one statically selected action item.
InterpretSends<Interpreter, RootEvent, Path>TraitExhaustively interprets one complete send product in structural order.
SourceSettlementCustody<Host, RootEvent>TraitOffers at most one emitter-return settlement input in declared order while retaining the exact residual product.
SourceCustody<Residual>EnumDistinguishes an exhausted product, exactly one admitted input, and closed admission with complete residual ownership.

These are statically dispatched interpreter obligations. A composite send product cannot silently omit a lane: the concrete interpreter must implement every required capability or fail to compile. Source custody uses the same declared order, but returns after one successful admission so the runtime can process that input and all transitive effects before offering the next one.

Staged creation and lifecycle result types

Creation values and outcomes

TypeKindSemantic role
CreationIdNewtype structOpaque correlation within one statically declared child occurrence; it is not an address, route, identity, or provenance.
CreationSequenceStructChecked source of non-reused IDs. Retaining one per occurrence is sufficient; one owner may share a sequence across several occurrences for a stronger guarantee.
CreationKindEnumBehavior-owned intent: ordinary Birth or fresh Replacement { previous }.
CreateChild<A, New>StructPure staged request containing a creation ID, owned child behavior, and creation intent.
Creations<Item>StructOne ordered creation batch. Runtime route preparation accepts the whole batch or returns it untouched.
RoutedCreation<A, New>Hidden structInterpreter-private pairing of a complete creation with its selected runtime route.
AllocationRejectionEnumTyped fresh-address failures: exhaustion or already-claimed proposed address.
ChildNamespaceExhaustedStructThe interpreter cannot route the complete declared creation batch without partial route consumption.
CreationRejectionEnumComplete rejected-child reasons after routing: allocation, initialization, or environment/commit failure.
CommittedChild<C, Occurrence>StructOne committed child's ID, creation kind, occurrence, and exact installed C actor.
EstablishedCreation<C, Occurrence>EnumNamed Installed(CommittedChild) or Rejected result for one concrete child occurrence.
ObserveCreation<P, Occurrence>StructSame-action request for the exact protocol/occurrence creation result; returns CreationResolved<P::Addr> and depends on CreationCorrelation<P, Occurrence>.
ChildDelivery<P, Occurrence>StructSame-action public-protocol delivery to a declared creator-local child occurrence.
ChildInput<Child, Source, Input, Occurrence>StructPrivate typed input to a concrete declared child event lane.
ChildReport<R>StructParent event payload containing the interpreter-attached creation ID and owned report.

Creation is staged, not performed by CreateChild. Behavior issues a CreationId and emits the child in the same transition. Exact correlation is the static child occurrence together with that ID. Independent layers may use equal numeric IDs for distinct occurrences; reuse within one occurrence remains invalid. The interpreter privately selects routes for the complete Creations batch before it hosts any child. A creation becomes established only after fresh allocation, initialization, installation, commit, and binding. Behavior never constructs or stores a runtime route.

Heterogeneous creation products

TypeKindSemantic role
Children<A, Product>StructBuilder for a pure ordered heterogeneous product of staged direct-child creations.
NoChildrenUnit structEmpty heterogeneous creation product.
ChildCons<A, C, Earlier>StructOne creation appended to an earlier heterogeneous product.
ChildProduct<A>TraitSealed recursive conversion from Children's product into one ordered Creations batch over a closed child choice.

Each Children::child or Children::create call adds one new structural child occurrence, so conversion into Creations is total. Equal IDs in distinct occurrences remain distinct correlations. Runtime route exhaustion returns the entire batch through ChildNamespaceExhausted.

Closed birth and topology type algebra

Birth capability and child sums

TypeKindSemantic role
BirthModeTraitAssociates a behavior with its closed child type algebra.
NoBirthsUnit structBirth mode whose child algebra is Never.
Births<C>Zero-state structBirth mode admitting closed child algebra C.
ChildChoice<Head, Tail>EnumClosed recursive heterogeneous sum of concrete child behaviors.
ChildHeadUnit structStructural position selecting a sum's head.
ChildTail<Position>Zero-state structStructural position selecting inside a sum's tail.
ChildPosition<Children, Child>Sealed proof traitProves that an exact child behavior occupies an exact structural position.
BirthNodeAppend<Tail>Sealed composition traitAppends one closed direct-child algebra after another while preserving existing positions and creation order.
BirthNodeAt<Position>Hidden sealed traitInverse projection from a structural position to its child type.

ChildChoice is a creation-only sum, not a message envelope, behavior trait object, registry, or runtime dispatcher.

Nominal child roles and occurrence resolution

TypeKindSemantic role
ChildRole<Parent>TraitAuthored proof that one nominal role names one exact direct child and structural position of Parent.
ChildOccurrence<Parent>TraitDeclares the sealed descriptor used to resolve one nominal or raw structural occurrence.
DeclaredChildOccurrenceHidden unit structDescriptor for an authored nominal child role.
StructuralChildOccurrence<Position>Hidden zero-state structDescriptor for a raw structural child position.
ChildOccurrenceResolution<Parent, Occurrence>Hidden sealed traitRestricts which descriptor may resolve a given occurrence.
ResolveChildOccurrence<Occurrence>Sealed traitResolves an occurrence against the concrete emitter, following topology-transparent BehaviorBase wrappers lawfully.
ResolvedChild<Emitter, Occurrence>Type aliasProjects the exact resolved child behavior.
ResolvedChildPosition<Emitter, Occurrence>Type aliasProjects the exact resolved structural birth position.
RoleChild<Parent, Role>Type aliasProjects the child behavior selected by one nominal role.
RoleProtocol<Parent, Role>Type aliasProjects the canonical protocol of a role-selected child.

Nominal roles distinguish duplicate occurrences even when they contain the same child behavior. A role and its structural position are topology evidence, not protocol identity, actor identity, or runtime lookup keys.

Interpreter dispatch and child occurrence products

TypeKindSemantic role
ChildCreationOutcome<C, Occurrence>EnumEstablished child, initialization rejection retaining child/error, caught pure-fold panic retaining the extant child, or host rejection retaining child/uninterpreted initialization actions/reason.
EstablishChild<Occurrence, C>TraitConcrete interpreter ownership port returning the fixed ChildCreationOutcome result for C at one exact occurrence.
ChildCreationProduct<A, Occurrence>Hidden traitRuntime-independent result product for a closed creation-only child sum.
DispatchBirth<A, Host>TraitExhaustive static dispatch over one closed creation-only child sum.
ChildOccurrenceShapeTraitDownstream type constructor defining empty and per-child representations for a direct-child occurrence product.
ChildOccurrenceProduct<Shape>Sealed traitSelects a shape-owned static representation for a closed direct-child algebra.
ChildOccurrences<Children, Shape>Type aliasOccurrence-preserving representation selected by one child shape.

These types let an interpreter prove support for every child alternative at compile time. They do not perform runtime protocol lookup or erase the child behavior type.

Protocol and host projections

TypeKindSemantic role
NoBirthProtocolsUnit structEmpty projected protocol product.
BirthProtocol<P, Tail>Zero-state structOne protocol occurrence followed by a remaining projected product.
BirthProtocolHeadUnit structStructural position selecting the current projected protocol.
BirthProtocolTail<Position>Zero-state structStructural position selecting inside the remaining protocol projection.
BirthProtocolAt<P, Position>Marker traitStatic membership evidence for one protocol occurrence.
BirthProtocolProductHidden traitClosed append operation over protocol products.
BirthProtocolsTraitProjects a behavior's own protocol and every protocol reachable through transitive births.
BirthNodeProtocolsHidden traitRecursively projects protocols from one closed birth node.
BirthNodeLogicalHostsHidden traitRecursively projects logical host requirements from one closed birth node.

Protocol products preserve repeated occurrences. They are static evidence and perform no allocation, hosting, normalization, or runtime lookup.

Finite sequence observation

The Behavior crate exposes no mailbox reducer or finite-stream result. Its contract ends at one initialization or event transition and the resulting Actions. Runtime scheduling belongs to Bombay. Repository tests use behavior_testkit::drive, whose Trace preserves the final active behavior, ordered sends and creations, initialization-inclusive transition count, pending mailbox suffix, and an exhaustive DriveDisposition distinguishing a drained mailbox from BehaviorStopped(Stopped).

Public companion operations

ItemKindRole
initializeHidden functionCanonical wrapper boundary invoking one inner initialization fold and returning its complete actions unchanged.
delegate_transitionHidden functionCanonical wrapper boundary invoking one inner event fold and returning its complete actions unchanged.
behaviorAttribute macroGenerates the mechanical Protocol, Behavior, BehaviorBase, closed send product, and closed birth-role wiring for an inherent impl.

For an actor named Actor, the macro may generate these concrete types when the corresponding declarations exist:

ActorSends
ActorSends<Field>                 one uninhabited selector per send lane
ActorActions                     fluent action-extension trait
ActorChildren                    closed ChildChoice alias
ActorChildren<Field>             one nominal role type per child declaration
ActorChild                       namespace containing role values

The exact generated Rust names preserve the actor and authored field names. The macro does not create actors, interpret effects, introduce a dynamic envelope, or grant capabilities absent from the handwritten core types.

Boundary summary

The crate intentionally stops at the pure algebra and minimal typed interpreter contracts:

  • Behavior consumes one event and returns Actions.
  • Actions owns sends, staged fresh creations, and next behavior or stop.
  • event, send, and birth products are concrete closed sums/products;
  • recipients distinguish logical identity from exact installed capability;
  • creation IDs remain creator-local correlation rather than actor identity;
  • interpreter traits realize typed effects without dynamic dispatch; and
  • reducers observe folds without becoming a scheduler or runtime.

Scheduling, mailbox transport, clocks, endpoint allocation, installation, effect settlement, and actor execution remain interpreter responsibilities.

Nominal Behavior attribute

#[behavior::behavior(...)] is the single generated authoring path. It preserves an ordinary inherent impl and emits the adjacent nominal Protocol, pure Behavior, optional named send product, and optional closed child product that a careful user could write by hand.

use behavior::{Actions, BehaviorActed, Delivery, MailAddr};

struct QueryPoolProtocol;
struct QueryStarter;

#[behavior::behavior(
    addr = MailAddr,
    message = behavior::Never,
    sends = {
        query_pool: Vec<Delivery<QueryPoolProtocol>>,
    },
)]
impl QueryStarter {
    fn init(&mut self) -> BehaviorActed<Self> {
        Ok(Actions::cont().send_query_pool(/* typed delivery */))
    }

    fn receive(&mut self, _: MailAddr, message: behavior::Never) -> BehaviorActed<Self> {
        match message {}
    }
}

addr and message are required because they establish public protocol identity. The other declarations are capability-denying defaults:

  • omitted sends means NoSends;
  • omitted births means NoBirths; and
  • omitted error means Never.

Those defaults do not infer or grant an effect. Code that tries to send, create, or return an error absent from the declaration fails to type-check. An advanced author may still supply an existing concrete sends or birth type instead of a generated { ... } product; this preserves handwritten catalogue products without adding another macro path.

Named send products

For an actor System, sends = { workers: Vec<Delivery<Workers>> } generates:

  • the nominal SystemSends product with a named workers field;
  • the uninhabited lane selector SystemSendsWorkers;
  • the SystemActions extension trait, with a fluent send_workers method;
  • SendEffects, preserving each field independently in declaration order;
  • SendInput<_, SystemSendsWorkers>, used through SendEffects::send;
  • SendsFor<Event>, requiring every field to be lawful for the complete event; and
  • InterpretSends, requiring and visiting every field in declaration order.

Two fields with identical product and payload types still have different lane selector types. No recursive position, type-name search, runtime registry, or catch-all effect value is generated. An interpreter missing any constituent delivery or request implementation fails its InterpretSends bound.

Generated fluent methods reuse the same Actions value and SendInput proof: they append exactly once to their named lane while preserving existing sends, creation order, and Continue, Goto, or Stop. They do not interpret an effect or introduce a second effect representation. Existing concrete send products remain directly constructible for advanced composition code.

Closed birth products

For an actor System, this declaration:

births = {
    workers: Workers,
    query_reply: ManagedQueryReply,
    query_starter: ManagedQueryStarter,
},
creation_settlements = return_to_creator,

generates SystemChildren as the exact recursive ChildChoice produced by calling Children::child_at in that declaration order. The generated behavior's birth capability is Births<SystemChildren>. The field labels record semantic roles. It also generates SystemChildrenRoutes, with one nominally distinct typed route per role. The same route stages that role's creation and constructs ChildDelivery<Child::Protocol, Role> or ObserveEstablishedCreation<Child, Role>, so dependent effects do not repeat an untyped nonce. Values and nonces remain explicitly authored.

These names extend the macro's existing generated namespace: SystemChild, SystemChildren, SystemChildrenRoutes, and one SystemChildrenRole marker for each field (for example, SystemChildrenWorkers). As with SystemSends and its lane selectors, callers must leave those actor-prefixed names to the macro. Using the same child behavior in two fields still produces two incompatible role types; sharing a protocol cannot accidentally exchange their routes.

The same declaration also generates the SystemChild selector namespace. Its inhabited values, such as SystemChild::Workers, implement ChildRole<System, Child = Workers>. Each role also carries a structural ChildHead/ChildTail<_> position proving where that exact behavior occurs in SystemChildren, and implements ChildOccurrence<System> for the sealed running-emitter resolver. This is the Behavior-owned proof consumed by static application topology and existing heterogeneous effect products:

Application::new(System::new())
    .child(SystemChild::Workers, workers)
    .child(SystemChild::Queries, queries)

The selector contains no nonce and performs no creation. SystemChildrenRoutes remains the separate creator-local routing product used when the parent stages creation and local dependent effects.

A route is routing intent only. It is not an actor identity, proof of freshness, or successful installation fact.

Generated and handwritten child products share the same sealed occurrence product. A static runtime may implement ChildOccurrenceShape once to project any SystemChildren into its own occurrence-preserving direct-child storage. The macro emits no runtime storage or shape implementation, and equal child types at two named roles still receive distinct structural positions.

Every real birth declaration must state who owns its completed creation settlements. creation_settlements = return_to_creator makes the generated event type CreationEvent<Addr, SystemChildren, Message> and requires an authored transition with this shape:

fn creations_settled(
    &mut self,
    settlements: behavior::CreationsSettled<behavior::MailAddr, SystemChildren>,
) -> behavior::BehaviorActed<Self> {
    // Decide from the exact accepted or rejected creation settlements.
}

Use creation_settlements = retain_for_retirement when the actor has no lawful transition for those runtime results. Its birth capability becomes RetirementBirths<SystemChildren>; the interpreter retains the exact settlement as terminal source custody rather than dropping it or manufacturing a no-op callback. Omitting births, or explicitly declaring NoBirths, needs no settlement policy because no creation request can exist.

ResolveChildOccurrence<Role> maps such a generated role to the exact child and position of the concrete behavior currently being interpreted. It follows BehaviorBase through wrappers only when they preserve both the canonical protocol and complete birth algebra. Wrappers that rewrite child topology do not inherit the base role; their own ChildHead/ChildTail<_> positions remain available. The mapping is sealed and type-level, not generated runtime code.

This is Bombay's staged creation policy: Children builds typed CreateChild requests, and the interpreter must commit them before dependent same-action sends and interpreter requests. The macro does not allocate, establish, replace, choose nonces, or infer lifecycle provenance. DispatchBirth still requires one concrete EstablishChild<Occurrence, Child> implementation for every alternative. The position distinguishes duplicate occurrences without making the role a protocol identity or forcing the parent type onto ordinary creation creation-result consumers.

Exact initialization and transition results

An optional inherent init(&mut self) -> BehaviorActed<Self> becomes the initialization fold. If it is absent, initialization returns the explicit empty Actions::cont(). The required receive(&mut self, from, message) -> BehaviorActed<Self> becomes the user transition fold. Rust checks both method results against the generated complete Actions<Addr, Never, Sends, Birth> and declared error type.

The macro generates no runtime context, constructor, scheduler, mailbox, executor, interpreter, or template policy. Initialization and receive bodies remain application-authored pure folds.

Why one attribute

Rust attribute macros transform an attributed item and their output is unhygienic. The implementation therefore resolves absolute paths through the direct bombay-behavior dependency or the bombay-rs facade, including Cargo renames. See the Rust Reference on procedural macros.

Serde-style stacked helper attributes are formally supported for derive macros, which can register inert helpers. An impl-level attribute macro has no equivalent helper-registration mechanism. Keeping sends, births, and errors as named sections of the one owning #[behavior] invocation avoids expansion order as an API constraint and keeps one coherent generated fold.

This construction is Bombay policy, not an actor-model primitive. Actions remains Bombay's typed realization of communications, fresh actor creation, and the next behavior or termination.

Behavior layer laws

This document is the acceptance contract for every same-actor behavior composition in Bombay. It is deliberately a semantic review rule, not another Rust trait hierarchy.

BehaviorLayer<B> has one narrow job: construct a fully concrete output behavior from B without forcing a generic owner to name that output type. The trait does not make an output lawful merely because the associated type implements Behavior. The concrete output behavior owns and must prove the event, effect, initialization, error, birth, and lifecycle transformation described below.

Provenance of the laws

Agha's actor calculus supplies the foundational boundary: an actor processes a communication, may send communications, create actors, and designate its next behavior. Actor configurations compose through their explicit receptionist and external-name interfaces. Agha does not specify Bombay's same-mailbox Rust wrapper order, typed event sums, typed effect products, initialization fold, controlled errors, shutdown protocol, or structural child occurrences.

Consequently:

  • single-communication processing, actor-owned behavior change, messaging to known actors, and fresh actor creation are actor-model laws;
  • Behavior, Actions, EventLayer, SendLayer, initialization ordering, creator-local child routing, and structural occurrences are derived Bombay constructions; and
  • wrapper precedence, error policy, shutdown policy, buffering, retries, and lifecycle reactions are deliberate Bombay policy choices owned by concrete behaviors.

References:

  • Gul Agha et al., A Foundation for Actor Computation.
  • Gul Agha, Actors: A Model of Concurrent Computation in Distributed Systems.

Construction is not transition composition

For a layer value L and behavior B:

L.layer(B) -> Output

is construction only. It must not initialize an actor, process an event, allocate an address, interpret an effect, or acquire a runtime capability. Output: Behavior defines the operational composition.

The blanket Fn(B) -> Output implementation exists only so ordinary concrete constructors and closures can be reused by topology owners. It is not evidence that two actor laws have been composed. A catalogue migration is complete only when the resulting concrete behavior satisfies every applicable law below and the former bespoke implementation has been deleted.

Do not add associated types, marker types, *Layer configuration wrappers, or aliases merely to make a generic call nameable. A new concrete wrapper is admissible only when it owns a distinct state or event/effect transformation.

Enforcement hierarchy

No single checker can establish these laws. The repository uses four complementary levels, in this order:

  1. this semantic contract decides what the behavior must mean;
  2. concrete Rust sums, products, capabilities, and compile-fail tests make representable invariants static;
  3. compiler and Clippy hard failures reject unsafe code, suspicious constructs, ignored must_use results, mutation hidden in debug assertions, placeholders, and unexplained lint suppressions; and
  4. pure-fold, model, exhaustive, property, fuzz, and interpreter-path tests establish the observable transition laws.

Broad style, complexity, and performance lint groups are review inputs rather than repository gates. They must not compel aliases, wrappers, boxing, helper traits, or reordered branches that obscure the actor algebra. Conversely, a lint suppression is not evidence that a semantic law holds. Clippy cannot prove effect conservation, error atomicity, lifecycle authority, initialization order, or higher-order reuse; those require the types and independent tests above.

L1: stable public capability

A transparent layer preserves B::Protocol exactly. A layer may change the public protocol only when protocol adaptation is its documented semantic law. Changing the internal event algebra, send product, child topology, error, phase, or state representation does not by itself create a new public destination identity.

The address namespace is preserved. A logical recipient, established recipient, creator-local child route, and established parent relationship keep their original routing intent through composition. A layer must not replace one with another to satisfy a bound.

L2: closed and single-owned event algebra

The output event is the exhaustive sum of its owned inputs and the preserved inner event algebra.

  • Every accepted event has exactly one semantic owner.
  • An inner event is injected once and delegated once.
  • An owned event is either handled by the layer or deliberately transformed into one exact inner event.
  • Equal payload representations from different sources or child occurrences remain distinguishable by their semantic source.
  • No implementation searches by payload type, wrapper depth, type name, or a runtime registry.
  • Adding an unrelated outer layer cannot change which existing law owns an input.

Public domain messages and private system inputs are members of the same closed Behavior::Event sum, but only the domain-message lane belongs to Behavior::Protocol.

Two ingress traits that differ only because Rust cannot prove their blanket implementations disjoint do not establish two semantic input laws. Such a split must be redesigned around explicit event ownership rather than exposed as architecture.

L3: one deterministic fold

One output event produces one Result<Actions, Error>. A layer does not run an interpreter, spawn work, call a clock, or perform another actor turn.

For a delegated event, the inner fold is invoked exactly once. For an owned event, the layer's documented transition is invoked exactly once. If an owned transition also induces an inner transition, the order and combined state commit are part of that layer's law and must be tested as one atomic fold.

Construction layers may be nested:

b.layer(first).layer(second)

Nesting is observationally associative with the equivalent composed closure: it must not change event ownership or action order merely because the caller grouped construction differently. This is observational equivalence, not Rust type equality.

L4: effect conservation

The output Actions product retains every inner effect and every layer-owned effect in semantically named lanes.

  • Inner sends are not dropped, duplicated, consumed, or reinterpreted.
  • The order within each inner lane is unchanged.
  • Layer-owned sends occupy an owned lane; positional .inner.inner access is not a public semantic interface.
  • Mapping sends preserves creations and the exact next-behavior verdict.
  • Mapping the verdict preserves sends and creation order.
  • A wrapper may consume an inner effect only when effect interception is its explicitly documented law and the replacement outcome is complete and observable.

The normal structural interpretation order is inner effects before outer-owned effects. A different order requires a named product, a stated reason, and complete order tests; it cannot arise accidentally from field layout.

L5: initialization conservation

Construction performs no initialization. Output initialization invokes the inner initialization fold exactly once unless construction or outer validation rejects before an actor definition exists.

For successful transparent composition:

  1. inner initialization effects retain their exact values and order;
  2. outer initialization effects are added in the layer's named send and birth lanes;
  3. the declared structural order is inner before outer; and
  4. the combined initialization become decision is explicit.

If initialization fails, no partial Actions exists. Validation or staged state changes performed before delegation must not leave the output in a partially initialized state.

Every pair of initialization-owning layers must be tested in both wrapper orders. Commutativity must never be assumed.

L6: controlled-error atomicity

An output error is a truthful exhaustive sum of inner failures and failures owned by the layer. It must retain the rejected input and any other owned value needed for recovery.

  • Delegated errors preserve the inner cause without reclassification.
  • Returning Err emits no partial effects.
  • State needed by a retry remains unchanged unless the documented error law says ownership was consumed.
  • A layer cannot mutate one submachine and then discover that another submachine rejects the same transition.
  • Expected availability, capacity, overlap, stale-input, and shutdown outcomes do not become opaque actor crashes after mailbox admission. They are successful typed responses or reports when a customer can recover.

Compiler difficulty coordinating two mutable folds is evidence that their joint transition has not yet been modeled atomically; it is not permission to add a wrapper or weaken an error bound.

L7: birth conservation and freshness

A transparent layer preserves the complete inner birth algebra. A topology-owning layer appends its children as distinct structural occurrences.

  • Inner creations retain order, concrete child behavior, nonce, and CreationKind.
  • An inner child is never reinterpreted as a layer-owned child.
  • Duplicate protocols remain distinct occurrences.
  • A nonce remains correlation data, not an address or freshness proof.
  • Same-action creation dependencies retain Bombay's creation-before-send interpretation policy.
  • Replacement provenance is carried explicitly and cannot be inferred from address or sequence reuse.

A layer that changes topology must expose the changed birth algebra. It may not claim transparent topology merely so an old role or interpreter continues to compile.

L8: next behavior and lifecycle authority

The inner Continue, phase change, or termination verdict is preserved unless the layer owns a documented lifecycle law that changes it.

Exactly one layer owns each lifecycle fact. Observation, shutdown, replacement, timeout, retry, and termination facts retain their source and generation. Duplicate, stale, contradictory, and late facts have exhaustive outcomes. Shutdown is defined in every intermediate state.

An outer lifecycle layer may suppress an inner verdict only when its state sum explicitly represents why and what later event completes the decision. It may not use a boolean, inferred ordering, or a later cleanup branch to repair a temporarily invalid combination.

Wrapper order is policy. For example, StopOnShutdown<Stash<B>> and Stash<StopOnShutdown<B>> are not presumed equivalent; each applicable order must either have a documented law and tests or be statically unavailable.

L9: higher-order reuse

A higher-order actor may retain a separate implementation only for a genuinely joint law that cannot be expressed by composing existing concrete behaviors. The review must name the correlated state and prove why separate actors or ordinary same-actor layers would alter the semantics.

It is not sufficient that two implementations call the same private helper. If a higher-order template merely selects, parameterizes, or translates an existing behavior, it must be ordinary typed composition and the duplicate fold must be deleted.

Examples of required review:

  • keyed affinity should be a layer over the ordinary pool unless key binding is inseparable from the pool's assignment/termination commit;
  • fixed supervision may own one shared fleet state machine, but pools must not copy its restart, installation, or shutdown transitions; and
  • a queue inside a pool is reusable only when its ownership, admission, completion, and interruption laws are actually the same—not merely because both use FIFO storage.

L10: static metadata follows the real algebra

Protocol hosting, interpreter obligations, and birth requirements are structural projections of the concrete output behavior. They must not be owner-authored duplicate lists, runtime registries, or aliases that repeat an already inferable composed type.

Static proof traits may expose an associated product when a generic framework must consume the product. Such a trait is metadata, not an operational layer, and its tests must use the real owner/interpreter path rather than a synthetic lookalike proof.

Required evidence

A concrete layer is not accepted by a compile-only example. Its evidence must cover every applicable item:

  1. construction without naming the output behavior type;
  2. complete initialization Actions and order;
  3. every owned event and a delegated inner event;
  4. complete sends, births, and next verdict;
  5. inner and owned controlled errors with state conservation;
  6. both relevant wrapper orders;
  7. duplicate, stale, contradictory, and shutdown lifecycle facts;
  8. a complete outer interpreter path for every new effect capability;
  9. an independent model or exhaustive trace for stateful laws; and
  10. restoration or simulation of the original defect proving that the regression fails for the intended reason.

Assertions observe a completed transition. They never perform the transition, move required state, or call a required function inside the assertion.

Rejection checklist

Reject a proposed layer or helper if any answer is “no”:

  1. Does it own a distinct state or event/effect transformation?
  2. Is every event owned exactly once?
  3. Are inner effects, births, errors, and verdicts conserved?
  4. Is initialization order explicit?
  5. Is failure atomic across every coordinated state machine?
  6. Does it work through every relevant existing wrapper order?
  7. Does it delete more bespoke caller machinery than it adds?
  8. Can a user construct the composition without naming its output type?
  9. Do tests exercise the public behavior law rather than its helper types?

A compiler error is diagnostic evidence for this review. Passing the compiler is the final representation check, not the design criterion.

Established capabilities

This document defines the production contract for runtime-issued exact actor capabilities. It does not claim that a downstream runtime has already adopted the contract.

The shared TerminalOutcome preserves the distinct execution cause Crash::CapabilityFailed when live execution acquires a capability task failure as its primary stop cause. It differs from a Behavior failure, affine Environment failure, actor-task panic and owner cancellation. Bombay owns detection, retirement, joining and full recoverable result custody; reusable actor templates preserve the supplied cause and apply their explicit policies. An operation failure discovered after an actor has completed remains a coexisting full-result fact and does not rewrite that actor's terminal outcome. A returned domain rejection is interpreted by its owning policy and is not automatically this crash cause. Cancellation selected first remains the primary cause even if a capability failure is also available; the full runtime result retains that failure.

Semantic classification

Actor-model laws:

  • actors may communicate only through acquaintances they possess;
  • actor names may be communicated; and
  • creation allocates a fresh actor name.

Derived Bombay constructions:

  • protocol-indexed endpoint families selected by a runtime-owned address type;
  • opaque inert recipient capabilities;
  • structural child occurrences and named effect products; and
  • distinct protocol and concrete-behavior capability strengths.

Deliberate Bombay policies:

  • a behavior stages creation with a CreationId that is non-reused within one statically declared child occurrence before allocation;
  • all creations in one Actions value commit before dependent sends or interpreter requests from that value;
  • successful creation reports an exact installed concrete actor;
  • observation and orderly shutdown have explicit correlation identities and complete accepted/rejected fact algebras; and
  • public interpretation traits are power-user authority boundaries.

Capability ladder

logical name                     exact protocol endpoint

Recipient<P>                    EstablishedRecipient<P>
    │ address lookup                 │ endpoint transferred directly
    ▼                                ▼
Delivery<P>                     EstablishedDelivery<P>

CreateChild<A, C> --commit--> CommittedChild<C, O>
          │                        │ ID, kind, occurrence, actor
          │                        ▼
          └───────────────> EstablishedCreation<C, O>
                                   │ Installed or Rejected
                                   ▼
                            EstablishedActor<C>

Recipient<P> is a typed logical name. It remains necessary where a stable name, external address, discovery result, or transport address is the intended semantics. Resolving it to a live endpoint is runtime work.

EstablishedRecipient<P> is an inert capability for one exact protocol endpoint. Its representation is <P::Addr as RecipientAddress>::Established<P>. It exposes no endpoint accessor and no direct send method. Transfer occurs through the public InterpretEstablished<P> boundary, so this is a power-user API boundary, not exclusive runtime authority. It does not prove which behavior is installed.

EstablishedActor<B> retains the runtime-owned Installed<B> value. That value projects the exact protocol endpoint and carries lifecycle authority for the same installed B. Its public constructor accepts only this one installed value. Message-only consumers may project an EstablishedRecipient<B::Protocol>; that projection cannot recreate the stronger actor. Generic orderly shutdown transfers the full B value and typed ingress without address lookup.

Why the address owns both capability families

An address used only for exact messages implements RecipientAddress. An actor-hosting namespace implements EndpointAddress, which supplies both projections:

impl EndpointAddress for RuntimeAddr {
    type Established<P> = RuntimeEndpoint<P>
    where
        P: Protocol<Addr = Self>;

    type Installed<B> = RuntimeInstalled<B>
    where
        B: Behavior<Protocol: Protocol<Addr = Self>>;

    fn recipient<B>(installed: &Self::Installed<B>) -> RuntimeEndpoint<B::Protocol>
    where
        B: Behavior<Protocol: Protocol<Addr = Self>>,
    {
        installed.recipient()
    }
}

This preserves static dispatch without imposing an associated endpoint or key on every domain protocol. Each concrete P, including a generic instantiation, produces a distinct EstablishedRecipient<P> capability type. The runtime may reuse one message endpoint representation across protocols; Installed<B> remains indexed by the concrete behavior because two behaviors can share P while accepting different events. There is no hashing, TypeId, dynamic dispatch, erased storage, or manually authored protocol key.

The associated endpoint must be Clone, because an established recipient is transferable acquaintance evidence. It is deliberately not unconditionally Send. Local interpreters may use closure-owned or otherwise thread-local endpoints. InterpretSends requires the complete concrete delivery or request to be Send when an asynchronous interpreter moves it, which naturally requires both the endpoint and P::Msg to be sendable on that path. This keeps executor policy out of inert capability construction and avoids propagating a false P::Msg: Send obligation through local creation, observation, and shutdown facts.

MailAddr intentionally implements only Address. It is a neutral logical address used by pure examples and tests, not a commitment to a runtime endpoint representation.

Creation transaction

CreateChild<A, C> owns one creator-issued CreationId, concrete child C, and explicit birth or replacement intent. The runtime interprets the ordered creation batch and each routed child as a transaction:

prepare one route for every creation without partial consumption
    -> allocate fresh address
    -> initialize child
    -> interpret initialization actions
    -> install exact endpoint and matching B::Event control
    -> commit creator-local (protocol occurrence, CreationId) binding
    -> issue EstablishedActor<B> and publish CommittedChild<B, O>

Route preparation rejection returns the complete untouched batch with ChildNamespaceExhausted. After routing commits, any failed child step publishes a rejected creation result and commits no binding. The owning ChildCreationOutcome settlement separately retains the current child and exact initialization value. The child rejection sum is:

  • Allocation(Exhausted | AddressAlreadyClaimed);
  • InitializationFailed; or
  • EnvironmentFailed.

The allocator's fresh address is independent of CreationId. Address has no derivation operation. A CreationSequence retained by one child occurrence makes reuse within that occurrence unrepresentable. Independent occurrences may issue equal numeric IDs because the occurrence is part of every binding. Stable identity and replacement are higher-level constructions; replacement never means overwriting an address.

A static runtime can derive its creator-local binding product with ChildOccurrenceProduct and a runtime-owned ChildOccurrenceShape. The sealed product retains each direct behavior leaf together with its existing structural occurrence; the runtime decides what endpoint and nonce storage that leaf contains. It adds no runtime value or capability to Behavior, and it does not flatten descendant actors into the current creator's namespace.

Effects retain their nominal occurrence rather than the running wrapper type. ResolveChildOccurrence<O> maps that occurrence back to the exact direct child and position for the concrete emitter. Generated roles pass transparently through wrappers only when Behavior::Protocol and Behavior::Birth are both unchanged. Raw structural positions always refer to the emitter's current birth node, including a topology-changing wrapper's proxy child. No endpoint, binding, or runtime lookup is performed by this type-level resolution.

ChildCreationOutcome<C, O>::Established directly owns CommittedChild<C, O>: ID, CreationKind, occurrence, and exact actor. It cannot nest a rejected EstablishedCreation. The later EstablishedCreation<C, O> report uses the same committed product on success and a typed CreationRejection without authority on failure. The parent behavior is absent from the report type; C is the actual child behavior, not a protocol-only guess reconstructed after the fact.

Same-action local delivery

ChildDelivery<P, O> carries only the child protocol, structural occurrence, nonce, and message. The active parent instance supplies the creator namespace as interpreter context. The interpreter resolves its committed local binding; it does not derive an address or consult an application-wide protocol table.

If the corresponding creation was rejected or no binding exists, delivery must fail through the interpreter's typed error. It may not be silently dropped, redirected, or resolved to an older incarnation.

Exact observation

ObserveEstablishedCreation<C, O> requests the committed result of a staged creation. It returns EstablishedCreation<C, O> to the emitting behavior.

ObserveEstablished::new(id, recipient) constructs one affine whole request with a freshly allocated private correlation. Construct the request outside every Behavior fold, then transfer it into the owning Actions lane; a Behavior may own or emit that prepared request, but does not issue fresh request identity during its fold. The observer-local numeric ObservationId selects a registration slot, not cancellation authority. A never-accepted whole original returned by rejection may be serially retried with its original correlation. New construction always issues a new private correlation, even for the same id and endpoint. Acceptance consumes the original, including when later Started publication fails; it never reconstructs a rejected Observe request after commitment.

ObservationAuthority<P> owns one protocol-indexed permission to attempt cancellation of an exact accepted relationship. It is affine, not a claim that the observed actor or membership is still live. The advanced interpreter consumes the complete Observe request when issuing the original authority, commits its same identity in its sole membership owner, and only then publishes Started. Public interpretation and issuance remain trusted advanced-host boundaries; the type system does not prove that a custom host actually committed membership.

ObservationRelationship<P> is cloneable nonauthorizing identity. It owns one strong Arc<ObservationId> and an invariant protocol brand; the numeric ID is derived from that allocation. Its read-only identity may be compared with a runtime-owned membership value. It cannot be publicly reconstructed, rebranded, or converted back into cancellation permission. Each new request owns fresh identity even when its numeric slot is reused; acceptance transfers that same original identity into the committed relationship.

CancelObservation::new(authority) consumes the exact protocol-matched grant. The request owns that grant until successful cancellation consumes it into a nonauthorizing receipt, or rejection returns the whole original request. Retrying that rejected cancellation retains the same relationship, not a fresh Observe attempt. EstablishedObservation<P> reports exactly:

  • Started { authority };
  • Stopped { relationship, outcome, at };
  • Cancelled { relationship };
  • ObserveRejected { request, reason }; or
  • CancelRejected { request, reason }.

Stopped carries no actionable permission. Every rejected Observe or Cancel retains its complete original request. Duplicate live numeric slots reject an Observe with IdAlreadyBound; a missing exact relationship rejects a Cancel with NotObserved, including when another relationship now occupies that ID.

The interpreter serializes completion's irrevocable decision to admit a Stopped fact and exact-member removal against cancellation. Cancellation winning that cut publishes Cancelled and permits no later Stopped. Completion winning the cut publishes Stopped and returns a later Cancel as NotObserved. If conversion occurs outside the membership guard, NotObserved may arrive before Stopped; this does not turn a cancellation rejection into an observation terminal fact. Retirement takes the same notification-admission owner before draining control. An already acquired converted event that cannot be admitted remains an original returned event in the existing task hierarchy.

The exact monitor owns one target control sum, emits its original Observe once, and consumes Started only when its request correlation matches. Its cancellation transfer must be returned in the aggregate's typed Actions lane. A rejected cancellation coexists with eventual Stopped and remains consumingly recoverable; its arrival does not suppress the terminal reaction. Monitor into_parts and the target's consuming rejection methods preserve all original current values on the wrong extraction kind. StopOnShutdown::into_inner consumes that wrapper without inventing mutable active-actor authority.

Legacy address-based ObservePeer<A> remains a different operation. It asks a runtime to select an incarnation by logical address and therefore still needs name-resolution policy. It must not be described as equivalent to exact capability observation. Its total action settlement accepts with unit after the relationship is established, or returns the complete request with PeerObservationRejection::UnknownAddress when neither a live incarnation nor authoritative retained termination can be selected. It has no prerequisite; missing interpreter support is corruption rather than unknown-address rejection.

Exact orderly shutdown

ShutdownEstablished<B, TargetPath> combines:

  • EstablishedActor<B>;
  • an observer-local ShutdownId; and
  • Ingress<ShutdownRequested, TargetPath> proving where shutdown enters B::Event.

The interpreter receives the exact installed actor and typed ingress. The request therefore remains an explicit event/effect transformation, not an ambient mailbox or runtime shutdown side channel. Immediate resolution is either Accepted or a typed AlreadyStopping/AlreadyStopped rejection. Later termination remains a separate observation fact.

ShutdownEstablished is an ActionItem under the repository's single total settlement law. Acceptance consumes the request and leaves its ShutdownId. Either lawful rejection returns the complete original request and exact actor capability. InterpretEstablishedShutdown can return only Result<(), ShutdownRejection>; it no longer selects an arbitrary output type. The request retains its original capability until acceptance and supplies a clone to the concrete admission port so rejection remains ownership-complete.

Runtime obligations

A conforming interpreter needs only capabilities justified by the values it drives:

  • one concrete message endpoint family and, for actor-hosting namespaces, one concrete installed B family with matching control;
  • fresh allocation independent of occurrence-local creation IDs;
  • creator-instance protocol-occurrence/CreationId bindings for local child effects, which may be derived statically from the sealed direct-child occurrence product;
  • exact endpoint delivery, observation, and typed shutdown interpretation;
  • logical-address resolution only for retained Recipient<P> paths; and
  • creation-before-dependent-effects ordering.

This contract can remove application-wide per-protocol actor spaces from exact internal paths. It does not make logical address resolution disappear where Recipient<P> is intentionally used.

Composition invariants

  • P remains the only protocol identity.
  • Structural occurrences are navigation evidence only.
  • Wrapping an emitter does not reindex an established or child destination.
  • Rejected creation carries no endpoint capability.
  • Exact capabilities are transferred only through Actions and explicit interpretation boundaries; they perform no ambient effect themselves.
  • Creation, observation, and shutdown correlation IDs are not actor identity.
  • No wrapper or domain generic is forced to implement Behavior unless an operation genuinely requires its concrete event or birth algebra.

Behavior adapter contract

An adapter drives one concrete B: Behavior. It owns execution and resource capabilities while the behavior owns state and semantic decisions.

Universal execution law

For each actor incarnation an adapter must:

  1. consume B through initialize exactly once;
  2. completely interpret initialization Actions before accepting mailbox events;
  3. process at most one accepted B::Event at a time;
  4. call transition exactly once for that event;
  5. if the fold succeeds, interpret the returned Actions exactly once; and
  6. commit its Continue, Goto, or Stop verdict exactly once.

A controlled fold error commits no partial actions. Cancellation or adapter failure must not manufacture a successful semantic fact.

Static boundary

The adapter is monomorphized over the complete behavior and its capabilities:

B: Behavior
B::Sends: InterpretSends<Adapter, B::Event, Here>
B::Birth::Child: DispatchBirth<B::Protocol::Addr, Adapter>

The concrete bounds vary with the host design, but every lane and child alternative must have a compile-time implementation. A universal driver may be generic; it may not erase events, effects, endpoints, futures, or child types to achieve universality. EndpointAddress itself does not require every endpoint to be Send. A thread-safe driver instead requires Send on the concrete Actions, request, event, endpoint, or future that it actually moves across its asynchronous boundary.

Actions commitment

For one successful Actions value, the adapter interprets:

  1. creations in vector order, reserving a fresh unpublished address, running each child's pure initialization fold, then privately committing its host, exact endpoint, and creator-local binding when those steps succeed;
  2. each committed child's initialization effects once before public publication or ordinary ingress;
  3. every named sends lane in its structural InterpretSends order; and
  4. the next-behavior or termination verdict.

All creation attempts precede sends and interpreter requests from the same action. This is a Bombay policy that makes create-then-send and create-then-observe deterministic. It is not a general actor-model ordering guarantee between independent actors.

Within SendLayer, inner effects are interpreted before wrapper-owned effects. Within a vector lane, values retain vector order. The algebra deliberately does not invent an order between independent product lanes beyond the product's own InterpretSends implementation.

An expected rejection retains its complete request and does not suppress independent later effects. Interpreter corruption retains the settled prefix, faulting value, and untouched suffix. Neither outcome can be reinterpreted as successful readiness, restart, or observation. A child whose private host was already committed remains an established birth even when its initialization effects later fail; it drains without public publication.

Fresh creation

CreateChild<A, C> contains a CreationId that is non-reused within its exact static child occurrence, a concrete child, and CreationKind. The adapter must not derive an address from the creation ID. Equal numeric IDs belonging to different occurrences remain different correlations.

For each ordered creation batch and routed request it must:

  • prepare every required runtime route without partially consuming the batch;
  • allocate an address fresh with respect to the actor configuration;
  • initialize the concrete child exactly once;
  • install a private runtime host, exact endpoint for C::Protocol, and matching C::Event control authority;
  • atomically commit the creator-local protocol-occurrence/CreationId binding;
  • report EstablishedCreation<C, Occurrence>::Installed after that commitment, without claiming initialization-effect success; and
  • interpret the child's initialization actions once, then make a continuing successful child publicly resolvable before ordinary ingress.

Failure before host commitment publishes no capability. Failure after private commitment preserves the established birth and its exact action settlement but does not publish the endpoint to logical resolution. After ownership transfer, InitializationRejected returns the current child and exact error, while InitializationPanicked returns the extant current child after a caught pure initialization panic, and HostRejected returns the current child, uninterpreted initialization actions, and matching CreationRejection. Before transfer, rejection returns the original creation batch with ChildNamespaceExhausted. An allocation collision is CreationRejection::Allocation(AddressAlreadyClaimed) when the selected allocator rejects it; it can never mean replacement.

DispatchBirth recursively selects the concrete child. One EstablishChild<Occurrence, C> implementation is required per structural occurrence. Position is interpreter navigation evidence, not hosting identity.

When the adapter retains exact child bindings, it may derive their complete direct-child product through ChildOccurrenceProduct. Behavior owns and seals the leaf, ChildChoice, and Never recursion; the adapter's ChildOccurrenceShape chooses only its storage constructor. The product is compile-time structure and performs none of the creation transaction above. Each installed child derives its own product from its own Behavior::Birth, so creator namespaces are not flattened or shared.

When an effect carries a nominal occurrence, require Emitter: ResolveChildOccurrence<Occurrence> and select the mapper-owned slot with its associated Position. This sealed projection accepts generated roles, raw ChildHead/ChildTail<_> paths, and genuinely transparent wrappers. It rejects inherited roles when a wrapper changes protocol or birth topology; an adapter must not repair that mismatch with a registry or runtime search.

Destination interpretation

The three delivery paths have different obligations:

RequestAdapter action
Delivery<P>resolve Recipient<P>::address() under the runtime's logical-name policy, then deliver P::Msg
ChildDelivery<P, O>resolve the current creator's committed (O, nonce) binding, then deliver
EstablishedDelivery<P>transfer the exact endpoint and deliver directly

The adapter must preserve P statically throughout. It may not coalesce two protocols merely because their addresses or message layouts match.

EndpointAddress lets the runtime's own address newtype select the endpoint family. InterpretEstablished, InterpretEstablishedDelivery, and the exact observation/shutdown interpreter traits are public power-user boundaries. They do not grant endpoint access outside the explicit transfer call, but they are not sealed as exclusive runtime authority.

Event injection

Interpreter-originated facts return through their declared ReturnsToEmitter<Input, Path>. The adapter retains the corresponding Ingress<Input, Path> or equivalent static constructor and enqueues exactly the root B::Event it produces.

Ancestor reports instead carry their destination ingress in the request and declare NoReturnToEmitter. For ReportShutdownPlan<P, Path>, the adapter calls into_event and enqueues that exact root event. It must not deliver the plan to the emitting inner lane, mutate the coordinator directly, or treat the request as successful installation before the coordinator consumes the event.

It must not inspect payload types to find a lane. Repeated fact types at different wrapper depths are distinct because their structural paths are distinct.

Observation

Exact observation uses ObservationId as observer-local relationship correlation and the supplied endpoint as incarnation identity. The adapter must return a complete EstablishedObservation<P> fact for start, cancel, rejection, or eventual stop. Duplicate live IDs and cancellation of a missing relationship are explicit rejections.

Address-based ObservePeer<A> remains separate. A missing live address is not proof that the requested incarnation stopped. Without a selected live incarnation or authoritative retained terminal fact, the adapter returns its own error rather than fabricating PeerStopped.

Orderly shutdown

ShutdownEstablished<B, Path> supplies an exact endpoint and a typed Ingress<ShutdownRequested, Path>. The adapter injects that event through the normal mailbox boundary. It returns EstablishedShutdownResolved<P>::Accepted only when the request is admitted, or the precise rejection otherwise.

The same attempt returns the generic action settlement: accepted leaves the exact ShutdownId, while AlreadyStopping or AlreadyStopped returns the complete ShutdownEstablished request. The concrete shutdown port returns only Result<(), ShutdownRejection> and cannot substitute another settlement shape.

Acceptance is not termination. Eventual termination is reported through the observation relationship.

Environment and liveness

Clock reads, timer queues, bounded-mailbox waiting, task scheduling, endpoint storage, networking, persistence, and operating-system failures are adapter concerns. They must enter or leave the fold only through declared typed events, effects, and errors.

Backpressure may delay a concrete interpretation future. The adapter must not silently drop or reorder accepted effects. Fairness, scheduling policy, and resource limits are runtime policy and should be documented by the runtime, not presented as laws of this crate.

Conformance checklist

  • initialization once and before mailbox events;
  • one event at a time and one fold per accepted event;
  • creations before dependent sends/requests;
  • fresh allocation independent of nonce;
  • rejected creation commits no binding or endpoint;
  • static interpretation for every effect and child occurrence;
  • exact endpoints bypass logical-name resolution;
  • all returning facts use their declared structural ingress;
  • ancestor reports use only the explicit ingress capability carried by the request;
  • no erased envelopes, registries, downcasts, or hidden side effects; and
  • no success, restart, stop, or observation fact is inferred from failed mechanics.

Exact observation ownership

The exact observation interpreter consumes the whole ObserveEstablished<P> or CancelObservation<P> request. It must preserve that original on rejection, commit the issued exact relationship before publishing Started, and consume a successful cancellation grant into its nonauthorizing relationship receipt. Stopped retains exact relationship, outcome and notification timestamp without retaining cancellation permission. Completion decision and cancellation share one membership owner; a reused numeric ID cannot authorize an old grant. A custom interpreter is a trusted issuance boundary, not a compiler-proven registration service. See Established capabilities for requests constructed outside folds, original input emission, serial never-accepted retry, both legal control arrival orders, and retirement admission custody.

Actor composition

bombay-behavior-actors exposes concrete actor folds and typed event/effect transformations. Applications connect those actors with ordinary typed composition. A constructor recipe is not a separate actor template when it only selects policy values, forwards to another constructor, or hides a nested type.

These compositions are derived Bombay constructions. They preserve the pure behavior boundary: one typed input produces complete Actions and a next behavior decision, while the interpreter alone realizes delivery, creation, observation, scheduling, and shutdown effects.

The composition map

There are two orthogonal ways to compose Behavior Actors. They may be used together, but they do not mean the same thing.

QuestionStatic constructionWhat it proves
Does another law transform this actor's mailbox fold?Behavior::layer with an existing concrete transformationthe complete resulting Behavior, including event, sends, births, phase, error, initialization, and next decision
May this actor send to a transferable destination?DeliveryRouteone exact protocol and its logical, established, or mixed concrete send product
Must a transferable destination use this actor's address namespace?DeliveryRoute<Protocol: Protocol<Addr = BehaviorAddr<Owner>>>the same logical, established, or mixed route, constrained to BehaviorAddr<Owner>
Which actors can this actor create?Behavior::Birth, BirthProtocolsthe closed, occurrence-preserving fresh-child algebra

LogicalHostRequirements separately derives the ordered product of every intentional logical Delivery<P> in the root and its transitive births, including interpreter requests that carry a logical recipient. It excludes established-incarnation delivery and creator-local child effects while retaining repeated protocol occurrences. A runtime may recursively require its own static Hosts<P> proof for that product; the projection creates no host and performs no lookup.

Same-mailbox layers

A layer constructs a new concrete behavior around one existing behavior. Both participate in one mailbox fold. Put the domain state machine at the center and add only transformations that own a distinct event/effect law:

StopOnShutdown                         root lifecycle transformation
└── ReceiveTimeout                     activity/timer transformation
    └── Stash                          bounded hold/replay transformation
        └── DomainBehavior             application transition law

Callers compose at the value level; Rust infers the full nested type:

let behavior = domain
    .layer(|inner| Stash::new(inner, |_, message| admission(message)))
    .layer(|inner| ReceiveTimeout::new(inner, timer, idle, on_idle))
    .layer(StopOnShutdown::new);

BehaviorLayer itself performs no actor effect. Each concrete transformation still owns and documents its event routing, initialization order, sends product, failure, and terminal decision. Reordering layers can therefore change the program and must be chosen from those laws, not from type convenience.

Actor-to-actor topology

Independent actors keep independent mailboxes. They compose through typed routes and explicit ownership, not by flattening their protocols into one envelope. Atomic actors have two intentionally different worker relationships:

FixedSupervisor ─┐
                  ├─> StableProxy ─> worker
DynamicSupervisor┘

FifoPool  ────────> direct worker
KeyedPool ────────> direct worker

The supervisors reuse the one stable-service and worker-replacement law owned by StableProxy. Pools own assignment, completion, recovery, and worker retirement directly; they contain no supervisor or stable proxy. A Router, queue, workflow, or domain actor remains a peer whose own transition law is connected through a typed transferable capability.

The short responsibility map is atomic-actor-architecture.md. The sole application-facing construction and worker-authoring syntax is atomic-actor-devx.md; this composition guide does not repeat either specification.

Choose the owner of the law

The catalogue is a vocabulary of state-transition laws, not a list of stacks that must always be used together:

Required lawOwning actor or transformation
domain state and protocolthe application behavior or one catalogue core
bounded admission or orderingBuffer, PriorityQueue, OrderGate, Sequencer, WorkQueue
one-recipient selectionRouter with RoundRobin, LeastLoaded, ConsistentHash, or RendezvousHash
fan-out to a membership snapshotTopic or PubSub
stable service identity across successive workersStableProxy
declared-roster coordinated recoveryFixedSupervisor
bounded keyed service membershipDynamicSupervisor
global FIFO jobs or keyed-affinity jobsFifoPool or KeyedPool
delayed replacementthe corresponding backoff supervision transformation
same-mailbox timing, observation, stashing, or shutdownthe concrete layer owning that transformation
ordered child shutdownShutdownCoordinator or HeterogeneousShutdownCoordinator

If two laws belong to different actors, connect them with DeliveryRoute. If one law transforms the same mailbox fold, construct it with Behavior::layer. If neither is true, the application is defining a new topology or a genuinely new transition law; hiding that fact in a generic wrapper would be incorrect.

Application routing and atomic actors

FixedSupervisor owns declared-roster recovery and DynamicSupervisor owns bounded keyed service membership. Neither also owns application command selection. Both rely on StableProxy for the stable service protocol and worker replacement, so application clients receive only the service capability—not a worker route or supervisor control capability.

A pool is different: it accepts customer jobs and owns direct assignment to its workers. It never exposes those worker routes. FIFO owns one global admission order; keyed pooling owns per-role queues and future-admission affinity. Their complete differences are owned by the two pool documents, not by a selector mode in this guide.

When an application command selects a worker, that selection is application state-transition policy. Keep it in the application behavior and emit a typed delivery to the chosen stable service, or place a concrete routing actor beside the supervisor and give it those capabilities. The supervisor remains responsible for recovery and stable service ownership; the router remains responsible for command admission and destination selection. This composition makes both protocols and both rejection laws visible to Rust.

Router is deliberately unicast and transfers ownership of a command to one selected route; it does not require the command to be Clone. Use Topic or PubSub when fan-out and its explicit cloning cost are the intended law.

Bombay application provisioning

Bombay must distinguish two creation owners:

  • Root::Birth contains only children the root behavior can itself create and correlate with creator-issued CreationId values.
  • Application contains peers provisioned by the application declaration.

An application child must therefore stop appearing in the root's births = { ... } declaration merely to make it runnable. That old arrangement forces the declaration to name the child's fully composed type before Rust can infer it. It is the source of aliases such as ManagedTask = StopOnShutdown<Task<...>>.

The application declaration should instead store each semantic slot and child value in its own heterogeneous product. Its private application-child owner keeps one sequence for those declarations and lowers the resulting values through the existing Children product. That sequence is independent of the root's creation state; equal numeric IDs remain distinct because root and application children occupy different static occurrences. Bombay selects runtime routes only when it interprets that creation batch. The public spelling contains values, not nested type declarations:

struct Tasks;
struct Events;

let application = Application::new(root)
    .child(Tasks, WorkQueue::new(worker).stop_on_shutdown())
    .child(
        Events,
        Topic::<MailAddr, Event, Recipient<EventSink>>::new()
            .stop_on_shutdown(),
    );

Tasks and Events are nominal application roles, not aliases for actor types. The expression passed to each child call determines the concrete child type. Each call returns the next inferred application-product type, so neither the composed child types nor the final Application<...> type is written by the caller. A zero-state generic actor such as an empty Topic still needs enough protocol arguments to determine its law; that is real protocol information, not a mechanical nesting alias.

Internally, Bombay needs one private application-child product with an associated Product: ChildProduct<MailAddr>. It should return Children<MailAddr, Product> after issuing IDs from the application-child sequence. The running application then uses exactly these Behavior projections:

type RootNode<R> = <<R as Behavior>::Birth as BirthMode>::Child;
type AppNode<L> = <<L as StageApplicationChildren>::Product
    as ChildProduct<MailAddr>>::Choice;
type RunningNode<R, L> =
    <RootNode<R> as BirthNodeAppend<AppNode<L>>>::Output;

impl<R, L, Routes> Behavior for RunningApplication<R, L, Routes>
where
    R: Behavior<Protocol: Protocol<Addr = MailAddr>> + BehaviorBase,
    L: StageApplicationChildren<Routes>,
    RootNode<R>: BirthNodeAppend<AppNode<L>>,
{
    type Birth = Births<RunningNode<R, L>>;

    // init:
    // 1. initialize R;
    // 2. issue one ID per application-child occurrence;
    // 3. lower L through Children::into_creates;
    // 4. call BirthNodeAppend::append_creations(root, application);
    // 5. rebuild Actions with the original sends and become decision.

    // transition:
    // delegate to R, then call append_creations(root_creates, Vec::new()).
}

BirthNodeAppend keeps RootNode<R> as an exact structural prefix. Existing root roles therefore retain the same child and position after application peers are appended. It also preserves every child value, creation ID, CreationKind, and within-lane order, with root creations before application creations. It does not allocate, install, or validate address freshness. Bombay still owns runtime route selection and must surface initialization-twice or child-product rejection as a typed private running-application error rather than panic.

This lets Bombay delete its root-shaped vacant-slot machinery: RuntimeApplicationTopology, EmptyApplicationTopology, VacantChild, OccupiedChild, AvailableApplicationRole, FillApplicationRoleAt, and InjectApplicationChildAt. A smaller role-indexed application product remains because it owns a genuine law absent from Children: semantic naming, deferred creation-ID issuance, and construction of runtime child handles.

The runtime must derive installation storage from the running application's combined birth algebra, not from Root::Birth. Consequently BirthProtocols automatically includes the root, genuine root children, application peers, and every transitive birth. Intentional logical destinations remain concrete in the composed send products. Behavior does not fabricate a completeness proof by asking the application to repeat those destinations in metadata, and Bombay must not add a protocol registry to compensate.

Unicast and broadcast in Bombay

Router is only unicast. Use RoundRobin, LeastLoaded, ConsistentHash, or RendezvousHash; each successful route transfers one owned message to at most one member. Bombay must remove stale Router<Broadcast> examples and imports, not recreate a broadcast strategy or compatibility wrapper.

Fan-out is the distinct Topic/PubSub state-transition law:

  • Topic<A, P, Route> owns one insertion-ordered membership snapshot; TopicMessage::Publish(P) sends a clone to every member.
  • PubSub<A, K, P, Route> additionally owns keyed topic introduction, known-empty retention, and per-topic membership; PubSubMessage::Publish { topic, value } fans out within one key.

Choose Route truthfully. EstablishedRecipient<P> broadcasts to exact installed incarnations and adds no logical-host requirement. Recipient<P> broadcasts to intentional logical identities, so the application topology must install that concrete protocol. For stable replaceable workers, subscribe the logical stable protocol, not a stale exact worker incarnation. Different destination protocols remain different actors and are connected with typed MessageAdapters; Topic never erases them into a common envelope.

Root shutdown

Use StopOnShutdown<B> when a shutdown request means that this actor stops directly. Use FinalizeOnShutdown<B> when shutdown must run one typed finalizer and preserve all of its sends, creations, and terminal decision. If shutdown must first be delegated to a coordinator, place that coordinator at the root; no guardian alias or builder is required.

These transformations compose like every other wrapper:

let direct = StopOnShutdown::new(application);
let finalizing = FinalizeOnShutdown::new(application, finalize);
let coordinated = ShutdownCoordinator::new(application, plan);

The choice is deliberate Bombay policy. It is not automatic discovery of a nested shutdown handler.

Plans derived from committed children

ShutdownCoordinator and HeterogeneousShutdownCoordinator own the distinct homogeneous and heterogeneous ordered-shutdown folds. A topology-owning application that cannot construct its plan until children commit records those committed EstablishedChild capabilities in its own state. Once complete, it emits ReportShutdownPlan::new(plan) in its ordinary Actions send product. The interpreter returns the corresponding typed InstallShutdownPlan<P> event to the coordinator.

The topology owner must preserve the following policy:

  • only a successfully committed creation contributes a child target;
  • rejection remains a typed application transition failure;
  • every declared role contributes exactly once;
  • an early shutdown request remains pending until installation; and
  • a plan installs at most once.

This is ordinary actor communication between two concrete folds. A generic child-plan wrapper cannot own these laws because it does not own the application's topology or role state.

Observation

Watch<B> is the recurring logical-name observation transformation. It continues observing later incarnations of the same logical peer. TerminationMonitor owns a correlated, exact-once observation lifecycle and consumes its terminal relationship. Exact-incarnation monitoring uses that same monitor law with an established target and an ordinary typed reaction.

Those recurrence laws are different, so they remain separate folds. Target aliases and established-watch wrappers add no law and are unnecessary.

Pools and shutdown products

FifoPool and KeyedPool each implement their public transition law directly. They may reuse private data helpers, but neither delegates its Behavior fold to a hidden generic actor engine. FIFO assignment and persistent key affinity have different state transitions.

Likewise, homogeneous and heterogeneous shutdown coordinators retain separate folds. Their phase products select different concrete child effect lanes, so a generic execution engine would hide the very distinction the public types are meant to prove.

Audit record

The complete catalogue classification and change ledger are in Actor-template composition audit. The broader capability and adversarial-test record remains in Behavior Actors template-law audit.

External actor-system interface

This note records the intended public boundary between a Bombay actor system and every external consumer: HTTP handlers, command-line programs, tests, embedded callers, and future authenticated transports. It is an architecture decision, not a claim that the downstream Bombay runtime already implements the complete contract.

Decision

Bombay should expose one transport-neutral, statically typed actor interface:

ActorInterface<Api>

Api is an application-defined named product of actor capabilities exported to the environment. The interface can also establish a real external actor/customer with a fresh typed address, an exact reply capability, and one affine receive authority.

Conceptually:

struct Api {
    orders: EstablishedRecipient<Orders>,
    discovery: EstablishedRecipient<ServiceDiscovery>,
}

let interface: ActorInterface<Api> = application.interface();
let mut caller = interface.external::<OrderReplies>()?;

caller
    .send(
        &interface.api().orders,
        OrderCommand::Get {
            reply_to: caller.recipient(),
        },
    )
    .await?;

let reply = caller.receive().await?;

The names above are illustrative. The semantic contract, rather than a particular spelling, is the decision.

The interface is not the actor runtime. Scheduling, mailbox interpretation, allocation, transport, topology ownership, and lifecycle control remain private runtime responsibilities. In particular, an untrusted external consumer does not receive the complete application topology or root shutdown authority merely because it can communicate with exported actors.

Source classification

Actor-model law

An actor configuration exposes receptionists: internal actor names known to the environment. It may also know external actors: actor names outside the configuration. Communication can expand these sets by transferring actor names. This is the actor-model basis for an explicit interface formed from exported actor capabilities and real external customer endpoints.

Primary sources:

The actor model does not require a global application router, a service registry, a public/private modifier on behavior types, or a generic ask operation.

Derived Bombay construction

  • Api is a closed, statically typed product that names the initial receptionist set.
  • An external actor owns a fresh address, a cloneable exact send capability, and an affine receiver.
  • A request carries its reply capability explicitly. User::from records the truthful origin of the communication; it is not implicitly the reply protocol.
  • Logical and exact destinations remain distinct. A stable logical name may be appropriate for discovery, proxies, or transport. An exact recipient identifies one installed incarnation and must never retarget.
  • Discovery is an ordinary typed actor protocol that can return additional actor capabilities. It is not privileged runtime lookup.

Deliberate Bombay policy

  • Application composition explicitly chooses the initial exports. Root is not automatically public, and declared children are not automatically public.
  • HTTP, CLI, tests, embedded integrations, and future transport gateways use the same interface contract.
  • A future Zenoh/KERI boundary authenticates an external identity and decides which typed interface or capabilities it may receive. Authentication, serialization, and transport do not enter the Behavior algebra.
  • Lifecycle ownership and the external communication interface are separate capabilities.

Visibility law

Bombay does not need a PublicActor behavior marker or inferred visibility. The same behavior may be public in one application and private in another.

An internal actor is externally reachable exactly when:

  1. its capability occurs in the initial Api receptionist product; or
  2. an already reachable actor later sends its capability to an external actor.

An actor that has not crossed that boundary remains private because the external party cannot name it. Discovery changes reachability only by returning a typed capability through ordinary actor communication.

Discovery

Registry and Resolver already supply the basic reusable discovery construction. No new Behavior Actors template and no new Behavior Core algebra are required.

Passing only a discovery receptionist to a particular boundary is a valid application policy when discovery is intentionally the sole bootstrap capability. It is not a universal actor-system rule. Another application may export several static receptionists, only its root protocol, or no discovery actor at all.

A heterogeneous global registry would require erasure or a closed application-specific protocol product. Bombay must not add an untyped global envelope, runtime protocol registry, Any, or string-based lookup to simulate heterogeneous discovery.

Request and reply

Actor-native request/reply is customer passing: the request contains a typed reply capability. A truthful external caller therefore needs a real endpoint that an internal actor can retain and use. Fabricating the target address as the sender, using an unclaimed raw address, or treating User::from as an implicit reply destination violates this contract.

The fundamental interface operation is external actor creation plus typed send and receive. A generic ask convenience may be derived later, but only after Bombay defines:

  • timeout ownership;
  • cancellation and overlap;
  • whether the reply actor remains live after caller cancellation;
  • late-reply handling;
  • correlation and stale-reply behavior; and
  • the typed result when an exact late delivery is rejected.

This is not cosmetic. In the current exact-delivery runtime contract, sending to a closed exact endpoint is an interpretation failure. Closing a temporary reply port on timeout could therefore make a correct but late reply fail the replying actor's action. Bombay must choose and test that policy explicitly rather than silently adopting dead letters or dropping the message.

Behavior Actors support

The catalogue audit classified every stored or received recipient by semantic role. All arbitrary customer/reply destinations are now parameterized by the sealed DeliveryRoute construction, which projects Protocol and Sends, instead of being hard-coded as Recipient<Reply>:

Route capabilityProduced effect
Recipient<P>Delivery<P>
EstablishedRecipient<P>EstablishedDelivery<P>
ReplyRoute<P>ordered ReplyDelivery<P> values retaining each logical/exact alternative

DeliveryRoute projects the protocol and concrete sends product from the route itself. Stateful templates such as dynamic supervision therefore cannot pair a retained route with an unrelated nominal reply protocol.

Creator-local child communication is not a transferable DeliveryRoute. Behavior retains a creator-issued CreationId; Bombay privately maps that ID and the statically selected child occurrence to its runtime route.

Registry membership, configured downstream destinations, worker completion targets, stable proxy identity, and transport names remain logical where that is their actual domain. The route migration changes only customer-passing seams. Compile-contract tests instantiate every such template with exact and mixed routes, while interpreter tests prove that a mixed lane neither converts capabilities nor reorders deliveries.

The shutdown coordinators also support creation-dependent topology. They may start in AwaitingPlan. The child composition constructs the plan only after every configured creation commits and emits ReportShutdownPlan through its returned Actions. The report's final destination is inferred from the complete static actor composition; application code supplies neither a path nor a route. Interpretation enqueues exactly one InstallShutdownPlan event for the owning coordinator. An earlier shutdown request remains retained until that event is folded. Homogeneous and heterogeneous plans are different event types and cannot be substituted. This is explicit Bombay lifecycle policy, not a new actor-model primitive.

Both additions live wholly in Behavior Actors and use existing Core events, effect products, exact recipients, child routes, and composition paths. No new Behavior Core algebra is required.

Rejected designs

The following alternatives fail the intended laws:

DesignReason rejected
Application::tell/ask as a central routerMakes the application object an ambient runtime service and obscures the sending actor.
Discovery as the mandatory only public actorConfuses one useful bootstrap policy with the actor-system interface law.
Publicness inferred from actor type or topologyVisibility is capability reachability chosen by composition.
PublicActor marker traitCouples reusable behavior semantics to one application's export policy.
Expose the complete topology handleLeaks private children and installation structure.
Give all clients shutdown authorityConflates communication capability with lifecycle ownership.
Fabricate target-as-originClaims an external actor identity and endpoint that do not exist.
Use User::from as reply capabilityProvenance and the reply protocol are distinct facts.
Dynamic heterogeneous registryRequires erasure, runtime protocol lookup, or a closed application-specific sum.
Treat generic ask as harmless sugarHides timeout, cancellation, and late exact-delivery semantics.

Required runtime work

The downstream Bombay runtime should implement this contract holistically:

  1. establish a fresh external actor endpoint with truthful typed origin;
  2. expose a named application-specific receptionist product;
  3. retain cloneable send capability and affine receive authority;
  4. keep exact recipients incarnation-bound and return the original message on admission rejection;
  5. separate the client interface from topology and lifecycle ownership;
  6. adapt HTTP, CLI, tests, and later transport gateways to this same boundary;
  7. preserve accepted-prefix draining and deterministic endpoint closure; and
  8. keep raw runtime address and mailbox representations private.

The complete composition must prove that a protocol mismatch cannot compile, receive authority cannot be cloned, private topology cannot be acquired from the client interface, a stale exact endpoint cannot retarget, and capability transfer can deliberately expand the reachable receptionist set.

Audit hypotheses

The architecture audit produced the following verdicts:

  1. A central application router is not the actor interface.
  2. Discovery is not universally the sole boundary.
  3. Publicness cannot be inferred from names or topology.
  4. Publicness is not a property of a reusable behavior type.
  5. The initial interface is an explicit typed receptionist product.
  6. Capability transfer may expand the reachable interface.
  7. An external caller must own a real endpoint and truthful origin.
  8. A fabricated or unclaimed origin is invalid.
  9. User::from is provenance, not an implicit reply protocol.
  10. Requests carry reply capabilities explicitly.
  11. Receive authority is affine.
  12. Send capability is transferable and cloneable where its endpoint permits.
  13. An exact capability never retargets to a later incarnation.
  14. Exact admission rejection preserves the rejected message.
  15. A logical reply route is not universally sufficient.
  16. DeliveryRoute supplies the existing static logical/exact abstraction.
  17. The public interface must not expose the complete topology.
  18. The public interface must not imply lifecycle authority.
  19. Generic ask requires a separate explicit lifecycle policy.
  20. The interface is transport-neutral and exposes no raw mailbox address.

These conclusions require no new actor template and no new Behavior Core algebra. The Behavior Actors route-capability and late shutdown-plan work is complete; the explicit unified interface itself remains downstream runtime work.

Atomic runtime interpretation and settlement

Status: H02 static representation proven; H07 has lowered total item, heterogeneous creation, and complete Actions settlement into Behavior; H10 fixes each named settlement product independently of the runtime; H03 records the required Bombay terminal-custody contract. Bombay will change to implement this architecture; its present interfaces do not constrain the atomic design. This document is the sole normative owner of generic action settlement, creation dependency ordering, initialization settlement, terminal custody, residual retirement, and the Bombay Engine integration requirement.

Ownership

Actions is Bombay's typed realization of actor transition effects: communications, staged fresh actor creation, and the next behavior or termination decision. It is not literally Agha's effect triple: typed products, termination, initialization, creator-local routing, and interpretation order include derived constructions and Bombay policy.

Behavior owns only pure static products. Bombay interprets concrete capabilities and owns runtime custody. Neither aggregate transitions nor generic Behavior machinery may contain tasks, clocks, channels, address spaces, observation publishers, callbacks, or runtime handles.

Total item law

For each declared item, interpretation produces exactly one outcome:

Accepted { receipt-or-promised-success }
Rejected { complete-original-item, exact-reason }
Blocked { complete-untouched-item, exact-prerequisite }

Blocked means a declared dependency did not commit; it is not a generic failure or a reason to suppress independent siblings. A corrupt interpreter result retains the recorded accepted/rejected prefix, the exact faulting item, and the complete unattempted heterogeneous remainder.

The product law is total and static:

  • lanes and items are interpreted in their declared stable order;
  • rejection does not short-circuit independent later items;
  • every accepted item is consumed and leaves only its specified receipt;
  • every rejected item returns its complete original value;
  • dependency-blocked items remain untouched with the exact prerequisite;
  • no positional traversal, runtime graph, erased envelope, callback, or per-template settlement adapter is permitted; and
  • a stopping actor is not required to receive its own settlement.

Any generic Behavior representation must prove this law through two unrelated catalogue templates and two wrapper orders without placeholders before catalogue migration begins.

Each action item fixes its accepted receipt, rejection, and prerequisite types. SendSettlements projects a concrete sends product to one complete settlement product without naming a runtime, root event, or structural path. InterpretSends may decide only the attempted outcomes within that fixed product. A stopping aggregate can therefore retain one typed settlement value without coupling its state to Bombay or adding a template-specific adapter.

The H02 non-production model satisfies that representation gate with a recursive heterogeneous product and the existing SendLayer inner-to-outer order. It preserves complete values after rejection/blocking, attempts independent later items, retains exact prefix/fault/remainder at every product position, and rejects a deliberate short-circuit trace. This proves stable-Rust realizability, not production implementation or Bombay custody.

Creation dependencies

Actor-model creation requires fresh allocation. A creating Behavior issues one checked CreationId, non-reused within the exact statically declared child occurrence, and emits the complete child in the existing creation leg. The occurrence and ID together are creator-visible correlation, not an address, runtime route, actor identity, or establishment capability. Independent pure layers do not share an ID issuer; equal numeric IDs in distinct occurrences are lawful. The interpreter commits a successful fresh creation before same-action communications or observations that name that occurrence and ID. This ordering is Bombay policy.

Creations owns one ordered creation batch. Bombay accepts that whole batch for routing or returns it unchanged with ChildNamespaceExhausted; it may not consume only a prefix. On acceptance Bombay privately pairs every request with one route from the current creator namespace, then the generic creation interpreter attempts each routed request independently in declared order. An expected child-establishment rejection does not suppress later creations or independent sends. Interpreter corruption retains the completed prefix and the exact routed remainder.

Behavior exposes no ChildRoute and never constructs an Address::Nonce. Bombay owns the private mapping from exact typed child occurrence plus CreationId to its runtime route. Child communications, lifecycle requests, reports, and creation prerequisites travel through that typed occurrence and carry its ID; runtime code resolves the pair to a route. An ID from one occurrence cannot satisfy another occurrence even when their numeric values are equal. A rejected routed creation remains in runtime settlement custody with its child, ID, kind, and selected route. Retirement transfers unresolved batches and routed creations through the same parent-to-root custody path as every other affine runtime value.

After a complete interpretation, one typed CreationsSettled input returns the entire creation leg to a live creator. The batch remains the ownership and ordering unit; templates do not rebuild a per-child settlement join. NoBirths requires no custody port. If creator admission is closed, the unchanged batch continues through parent-to-root custody.

There is no separate route request, result, aggregate waiting phase, or ReturnToEmitter continuation. Route preparation is the first generic step of interpreting the one creation leg through the unchanged Driver. It creates no mailbox, task, registry, callback, or lifecycle service.

An establishment attempt that accepts ownership of a child definition returns an authoritative ChildCreationOutcome<C, Occurrence>. Established owns the exact capability. InitializationRejected returns the current child and exact initialization error. InitializationPanicked returns the extant current child after a caught pure fold panic, without claiming a typed initialization error or actions. HostRejected returns the current child, uninterpreted initialization actions, and exact reason. These are semantic creation rejections, not interpreter corruption, and none reconstructs the pre-initialization child. Rejection or corruption before ownership transfer instead returns the complete original CreateChild through ItemSettlement.

A behavior declares that request through exactly one of two domain operations: CreateChild::birth or CreateChild::replacement. CreationKind remains authoritative carried provenance for interpreters and typed results; it is not a third, context-free application constructor. Closed child-product composition may reconstruct the same request internally while preserving its owned kind.

Semantic creation rejection blocks only operations whose typed prerequisite is the uncommitted child binding. After creation commits, rejection of one observation blocks only operations that depend on that observation; lawful child delivery, input, shutdown, termination observation, and unrelated observations remain independently eligible. The dependency relation is expressed by the concrete child-operation item type and its InterpretItem::Prerequisite: ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild are the only current same-action child families. The runtime transaction retains their typed resolution by exact child protocol, occurrence, and CreationId. ObserveCreation<P, Occurrence> returns CreationResolved<P::Addr>; it does not erase P to its address. No general dependency graph, lane index, or wrapper position is consulted.

A route collision can only falsify Bombay's accepted batch-preparation receipt; it is interpreter corruption, never replacement. Namespace exhaustion rejects the untouched batch before route transfer. Replacement provenance is explicit typed semantic data and never inferred from address reuse, route reuse, or sequence arithmetic.

Initialization and activation order

Initialization is part of the Behavior contract. Its actions are interpreted before ordinary mailbox ingress and compose with wrapper initialization in one defined order:

fresh address reservation, no live endpoint
  -> pure definition initialization fold
  -> endpoint installation and creator-local binding commit
  -> total initialization-action interpretation
  -> initialization settlement and residual custody
  -> activation authorization and attempt, where required
  -> exact readiness or failure fact, where required
  -> ordinary ingress only after a continuing, successfully settled initialization

Initialization may stop with final actions. Accepted initialization effects are settled before ordinary ingress, even when the resulting actor is stopping. Activation capacity is actor-side admission before an action is emitted; it is not relabelled as an interpreter rejection afterward.

Reservation rejection retains the complete staged creation without running the fold. Pure initialization rejection retains the current child and exact error. Host rejection after the fold retains the current child and uninterpreted initialization Actions. After installation commits, an effect rejection or interpreter fault belongs to the installed child's drain and cannot be recast as a creation rejection. A stopped initialization settles its final actions without permitting ordinary ingress. Fresh allocation is the actor-model requirement; this packaging and ordering are Bombay policy.

Exact Bombay changes for worker initialization and activation

Bombay must keep the installed child closed to ordinary traffic and retain its complete initialization-action settlement in the existing child lifecycle host. The settlement never moves into StableProxy state or a supervisor report. After ChildCreationOutcome::Established, an atomic owner retains its non-cloneable worker state and emits InitializeWorker<W, P>. That request contains only a cloneable exact worker target, opaque worker and initialization correlations, and the moved activation plan. It does not move the aggregate's worker, name the worker's action product, or search by runtime type.

The request is an ordinary ActionItem with accepted unit and uninhabited capability rejection or prerequisite. Bombay interprets it by locating the already existing child host through the supplied established target. Missing support is interpreter corruption, not an invented runtime rejection. The host calls InitializeWorker::resolve with exactly one WorkerInitializationOutcome::ReadyForActivation | EffectsRejected | Stopped result, which reunites that result with the affine plan as WorkerInitializationReport. The request and result run inside the unchanged Driver and retirement barrier.

Bombay's local environment must interpret that request through its exact installed-child capability. Acceptance transfers the request to the already existing child lifecycle host; it is therefore a non-rejecting local custody operation. Missing typed support is interpreter corruption and retains the complete request. It is not an expected mailbox, observer, or capacity rejection. When initialization settles, the host returns exactly one Tier-1 WorkerInitializationReport input:

ReadyForActivation { worker evidence, original plan, one activation permit }
EffectsRejected {
    worker evidence,
    original plan,
    failure: EffectsRejected | InterpreterCorrupt
}
Stopped { worker evidence, original plan, exact stop }

The host derives failure by inspecting the complete settlement's SettlementStatus without consuming that settlement. Accepted selects the Initialized alternative and cannot inhabit WorkerInitializationFailure. Expected capability rejection or dependency blocking selects EffectsRejected; interpreter corruption or an unattempted suffix selects InterpreterCorrupt. The exact settlement remains attached to the concrete worker environment. StableProxy drains the worker and reports only this semantic classification, its activation plan, and the exact worker result.

A foreign worker or initialization correlation returns the complete request and report unchanged. Failed creator admission follows RecoverEvent and the existing parent-to-root custody path. No template-specific Bombay conversion, second mailbox, or detached task is allowed.

If StableProxy admission closes, Bombay retains the complete WorkerInitializationReport input, including the activation plan, beside the worker environment's exact action settlement. Parent retirement transfer moves both values outward as one statically typed residual. This is not a lookup token and does not require StableProxy to reopen or consume its own settlement.

On Initialized, the aggregate consumes the permit and plan with a fresh activation attempt and exact worker target into BeginActivation<W, P>. Activation capacity is checked by the aggregate before this request exists. It is never reported as an interpreter rejection.

The selected Communication control capability has one rejection: ControlClosed, which returns the complete submitted value. Consequently the activation-start action has exactly one expected rejection, OwnerStopped, and that rejection retains the complete BeginActivation. Mailbox fullness, observer capacity, generic host failure, and activation capacity are not members of this sum.

ActivationPlan::activate(self) is a statically dispatched future. After accepting the request, Bombay must enqueue the matching Started input to the owner before polling the plan. It then retains the typed JoinHandle<WorkerActivation<W, P>> in the existing local environment, polls it with the existing input schedule, and returns the matching ready or rejected input through the unchanged Driver. Only an accepted request's consumed plan may produce readiness.

The H22 production contract realizes that shape without a task in Behavior. ActivationPermit retains the exact established worker target already supplied to the initialization host. BeginActivation::new therefore accepts only the returned plan and permit; no caller can substitute another same-protocol worker. A private activation correlation is reserved one-to-one from the permit's non-reused worker attempt. BeginActivation::started produces the WorkerActivation value holding the matching started alternative. Consuming BeginActivation::activate moves the plan exactly once to a WorkerActivation holding either readiness or rejection. The public runtime values expose consuming projections, not constructors for their private alternatives.

Bombay must own activation work in one statically typed task product within the actor's existing environment. Completed results return through the actor's ordinary typed system-input admission. Unfinished work and completed results whose owner admission has closed transfer through the existing retirement barrier to the root custodian. The task product retains its concrete output; it must not reduce it to JoinHandle<()>, abort and discard it, or detach it. This is Bombay runtime work, not a Behavior-side runtime. It introduces no second Driver, mailbox, erased output, or lifecycle service. Cancellation never claims physical cancellation unless the concrete plan provides it.

H14 supplies the generic ClassifySettlement projection over the complete H10 static settlement product. Bombay inspects SettlementStatus::Accepted, Rejected, or Corrupt without consuming or reconstructing that product and without template-specific traversal. Rejected includes both a capability rejection and a declared dependency block. Rejected or blocked effects take precedence over a simultaneous initialization stop; the unchanged next decision remains present in the complete settlement and the installed worker then drains normally. Corrupt includes an interpreter fault or any unattempted suffix and therefore enters the existing residual-custody path with the entire settlement.

ActionSettlements projects a concrete Actions type to this complete static settlement without naming an interpreter. BehaviorSettlements applies that projection to a concrete behavior without forcing lifecycle owners to restate the behavior's internal creation and send bounds. Lifecycle-host requests use the associated type when they must return a worker's initialization settlement; they do not restate the creation vector or send-product structure in each actor template. Both projections perform no interpretation and change no custody.

Named products interpret their fields in declared order. A corrupt earlier field retains the untouched later fields as unattempted; a lawful rejection does not stop independent later fields. The SendProduct derive and the #[behavior] generated products share the ordered traversal and source-custody generator while preserving their domain field names. The unused two-product tuple helper and the private Actors declarative macro were removed. Named products return complete named settlement shapes.

StableProxy's ProxyEffects declares worker observation, initialization, activation, shutdown, service delivery, owner outcome, and diagnostic lanes in that order. Runtime-local and structural-owner operations use the one InterpreterRequests product; service forwarding uses exact established delivery. A concrete compile witness proves the actual StableProxy::Sends implements InterpretSends, so no vector-only lane or template adapter remains. Creation is still interpreted first by Actions; therefore the observation's exact CreationCorrelation<WorkerProtocol, ChildHead> refers to that same action. Creation settlement and the later ChildStopped event are independent admissions. The proxy retains either arrival order explicitly and returns both values if creation rejection contradicts an already observed stop. Bombay must not serialize those admissions merely to simplify the aggregate.

Terminal custody

Every affine terminal settlement follows one ownership path:

child lifecycle host
  -> admitting parent
  -> next structural owner when parent admission is closed
  -> non-rejecting root custodian
  -> existing Engine retirement barrier

Closure returns the exact value; it never logs or discards it. Outward transfer does not reopen a stopped actor. The path uses the existing Driver and actor graph—no detached task, second mailbox, second lifecycle framework, or Behavior-side runtime is permitted.

Forced retirement transfers unresolved creations, initialization and activation settlements, assignment joins, customer outcomes, diagnostics, timers, shutdowns, and queued ingress as explicit residual ownership. Actor-graph retirement and external work are distinct; the root barrier cannot claim quiescence while externally owned terminal work remains unaccounted for.

An aggregate may retain its unresolved actor-owned values in a private terminal alternative of the final concrete behavior. Runtime work already accepted from that aggregate remains in the environment residual. Bombay transfers both products without inspecting, flattening, or reconstructing either one. This separation prevents a pool-specific residual lane while preserving the exact owner of every affine value.

FIFO and KeyedPool name the identical local stop cause once as ForcedRetirementCause: exhausted worker-shutdown identifiers, a deadline not scheduled with its complete interpreter result, or the exact elapsed deadline. The cause does not own a worker roster and does not perform transfer. Each aggregate retains its own unresolved workers; Bombay later moves the complete concrete behavior and environment residual together.

Exact concrete rejection vocabulary

Concrete reasons come from the selected locked dependency contracts:

  • asynchronous Communication send waits for bounded capacity and rejects only with the closed complete payload; Full belongs to try_send;
  • control send is unbounded and rejects only ControlClosed(complete_item);
  • Address claim distinguishes AddressInUse and permanent registration-ID exhaustion;
  • Observe distinguishes SubjectExists, UnknownSubject, and exact generation-checked retirement;
  • Timers use exact branded schedule tokens and exact-current cancellation; and
  • orderly shutdown distinguishes accepted, already stopping, and already stopped, with child absence separately reported as not established.

H23 places exact orderly shutdown on the same generic item settlement as every other action. Accepted exact shutdown leaves ShutdownId; either selected rejection returns the complete ShutdownEstablished request and its exact actor capability. The concrete endpoint port returns only Result<(), ShutdownRejection>. StableProxy can therefore use exact shutdown for post-commit worker drain without a proxy-specific adapter or weaker child route.

Generic settlement must not fabricate mailbox-full, observer-capacity, activation-capacity, or typed exhaustion variants unsupported by those APIs.

ObserveChild<P, Occurrence> names the concrete child protocol because its same-action dependency is the one existing CreationCorrelation<P, Occurrence>. The selected child-observation path clones the hosted exact termination observation after the typed child binding commits. It therefore has accepted unit, no capability rejection, and only the creation prerequisite; SubjectExists applies to subject registration and is not fabricated as a child-observation rejection. Equal address types do not make two child protocols substitutable.

H05 makes this boundary executable without adding runtime dependencies to Behavior. A research-local witness checks 13 exact facts against the selected Address 0.2.0, Communication 0.1.2, Timers 0.1.0, frozen Bombay Observe, and locked Behavior shutdown sources. Under Bombay's pinned Rust 1.96, the exact Address suite passes 14/14, the Timers suite passes 2/2, and Communication's library target builds (it has no library unit tests). These releases cannot be linked into the Rust-1.95 atomic experiment; that MSRV boundary is intentional evidence that concrete capability interpretation remains a Bombay concern.

Required Bombay target

The atomic architecture targets the following Bombay contract. Bombay's present method signatures are historical evidence only; they are not reasons to weaken, defer, or reshape the accepted actor laws.

Bombay must:

  1. return or re-home the complete rejected parent event;
  2. move the final concrete Behavior value into retirement ownership instead of dropping it after Step::Stop, Exhausted, or a Driver error;
  3. return a typed residual from environment retirement;
  4. carry the Behavior and environment residual through the existing Driver retirement barrier; and
  5. deposit that one typed transfer at a non-rejecting root custodian before the barrier releases.

Typed application assembly

Bombay must also reverse its current root-first application construction order for actor templates whose required destinations are application-owned actors. The target order is:

declare application actors by semantic role
    -> install them through Bombay's existing runtime ownership
    -> obtain their typed logical or exact capabilities
    -> construct the pure root from those capabilities
    -> initialize and activate the root
    -> return the typed root and application lifecycle capabilities

The one-time root constructor belongs to Bombay application assembly. It is not a Behavior, is never retained by an atomic actor, performs no I/O, and cannot be invoked from a transition. Bombay remains the sole owner of address allocation, mailboxes, installation, activation, and startup rollback. If peer installation or root activation fails, Bombay retires every already installed application actor through the same retirement path and returns the exact startup failure.

Application code names semantic roles, concrete actor behaviors, and typed capabilities only. It does not name MailAddr, child-product positions, occurrence paths, generated type aliases, or final composed behavior types. Role selection must be inferred and statically checked; the public source shape must not expose the existing TopologyAt cursor or ApplicationRoute product. No registry, dynamic capability map, erased protocol, second mailbox, second Driver, or atomic-template-specific host is permitted.

H139 shows why returning only ApplicationHandle<Root::Protocol> after root activation is too late. A full Start message happens to infer every dynamic type from its payload. The lawful Stop { key } message does not name worker or activation types, so current stable Rust reports E0283 at Application::new. Adding a turbofish, alias, explicit root type, fabricated Recipient, or dummy worker field is rejected. The lifecycle actor's concrete DynamicLifecycle<Key, Worker, Plan> protocol must supply those types during role-first assembly instead.

This application-assembly change and the retirement-custody change are separate Bombay responsibilities. Either may be implemented first, but both must use the existing Driver and both must pass the final atomic integration probe.

H148 historically derived the target source equation independently of Bombay's current root-first API: typed lifecycle and diagnostic capabilities enter one pure root constructor, the six-policy dynamic(entries, activation, unexpected_exit, actor_drain, lifecycle, diagnostics) call infers its key, worker, and activation types. The real production construction test and five command paths now own that contract; H589 removes the superseded facsimile while retaining H148's compiler evidence in Git. Removing lifecycle provenance or delivering Stop without the typed supervisor capability produced E0277/E0308 or E0282. Bombay must change its assembly order to supply this context; Behavior Actors must not add an annotation, raw address, callback, or alternate constructor to compensate for the present runtime API.

This is the required Bombay architecture. A stopped aggregate can retain complete affine terminal values in its private final state, so returning only environment state would still lose ownership. Bombay changes to carry both the final concrete Behavior and the environment residual. Atomic implementation may target this contract before the upstream patch lands; it must not add a local workaround. Final end-to-end verification records the upstream revision that supplies these five links. H03 authorizes neither a Behavior-side custodian nor a second Driver, mailbox, task, or lifecycle service.

Bombay's application facade re-exports only the non-hidden semantic names listed by atomic-actor-devx.md. Interpreter code may import the doc-hidden associated request, event, effect, and settlement types through behavior_actors::atomic; none becomes a second application spelling.

Required Bombay implementation

Bombay must realize the target through its sole Driver path. No Bombay source is modified by this campaign, but upstream will make the following coherent replacement. Applying only a subset leaves affine values unowned.

crates/bombay/src/interpret.rs

  1. Delete the InterpretationError<C, S> two-leg short-circuit sum. Expected capability rejection is data in ItemSettlement; it is no longer a commit error.
  2. Implement the generic creation leg in two stages. First, one InterpretItem<Creations<CreateChild<BehaviorAddr<C>, C>>, ...> call either returns the complete batch untouched with ChildNamespaceExhausted or returns one ordered Creations<RoutedCreation<BehaviorAddr<C>, C>> value. Then EstablishChild<Occurrence, C> settles each routed child independently. Its output is fixed by the routed creation, not selected by Bombay. Established returns the exact established capability. InitializationRejected returns the current routed child and exact initialization error. InitializationPanicked returns the extant current routed child after a caught pure fold panic. HostRejected returns the current routed child, uninterpreted initialization Actions, and exact reason. Corruption retains the exact routed suffix through InterpreterFault.
  3. Replace CommitActions::commit's creation for loop and subsequent InterpretSends::interpret(...).map_err(...) with exactly one actions.interpret::<_, B::Event, behavior::Here>(&mut self.capabilities) call. That call already owns creation-before-sends order, lawful continuation, heterogeneous residuals, and the exact become verdict.
  4. Return the resulting ActionSettlement to the existing host settlement admission. Do not discard it after checking Complete, and do not convert Interpretation::Corrupt into an error lacking the settlement value.
  5. Keep ActionInterpreter as the one concrete capability product used by the existing Engine Driver; add no loop, mailbox, task, registry, or adapter.

crates/bombay/src/application_runtime.rs

  1. Delete the blanket SendInterpreter implementation and migrate every InterpretRequest, InterpretDelivery, InterpretEstablishedDelivery, InterpretChildDelivery, and InterpretChildInput implementation to the single static InterpretItem<Item, RootEvent, Path> ownership port. Runtime implementations do not select a settlement associated type; ActionItem and SendSettlements already fix the exact result vocabulary.

  2. Each implementation must return its complete capability-specific sum:

    • async logical and exact delivery acceptance consumes the message and returns only its receipt; Unknown or Closed returns the original delivery and exact reason;
    • child delivery/input consults the exact occurrence binding. A rejected creation resolution produces Blocked { item, prerequisite }; genuine absence produces Rejected { item, MissingChild }; closed admission returns the original item;
    • timer scheduling uses only the selected Timers reason/token contract;
    • Observe uses only SubjectExists, UnknownSubject, and exact generation facts;
    • control ingress returns ControlClosed(complete event) instead of ignoring ControlSender::send;
    • child shutdown returns its exact accepted/already-stopping/not-established settlement and never reports success merely because a local fact was enqueued; and
    • ReportToParent<Report> returns the complete report when parent admission is closed.
  3. Replace the legacy nonce-oriented CreationResults with a typed current-action prerequisite store keyed by the exact declared child occurrence plus CreationId. Beginning an action clears only the prior action transaction. Equal numeric runtime routes and distinct occurrences cannot satisfy each other's prerequisite.

  4. Child hosting consumes RoutedCreation and returns ChildCreationOutcome<C, Occurrence> as its accepted receipt. Successful commit returns Established. A pure initialization error returns InitializationRejected with the routed child and exact error. A caught pure initialization panic returns InitializationPanicked with the extant current routed child. Allocation rejection occurs before initialization and returns the complete routed creation. Host rejection after initialization returns HostRejected with the routed child and still-uninterpreted initialization Actions. Post-commit initialization-action failure is not a creation rejection; it enters the created child's drain.

  5. Remove every let _ = control.send(...) and equivalent ignored ControlSender result. Each becomes an owned item settlement or terminal residual.

crates/bombay/src/local.rs and crates/bombay/src/launch.rs

CommitActions must expose the complete action settlement rather than Result<(), E>. Initialization follows the same path as active turns. A child is not published live until its initialization ActionSettlement has been admitted or transferred; an initialization Step::Stop still settles its final actions. A post-commit corrupt or rejected initialization effect drains the installed incarnation and retains all residuals; it cannot be mapped back to CreationRejection or roll back an accepted prefix.

For every creating behavior, host settlement owns one generic creation-entry pass before ordinary ingress. In authored order it moves each entry into ChildCreationSettled<C, Occurrence> and attempts the statically declared creator system lane. This is one generic Births<C> capability, not an atomic template adapter. A live creator receives the exact ChildCreationOutcome, including the non-cloneable child and initialization value on rejection. If admission is closed, the control send returns the complete root event; RecoverEvent<ChildCreationSettled<C, Occurrence>, Path> recovers the exact product and the lifecycle host retains it. A stopping creator may transfer the entry directly without reopening its mailbox. NoBirths requires no settlement lane or placeholder event.

The same mechanism must work for a non-atomic creating catalogue template and for an atomic aggregate before Bombay accepts it. The Driver does not inspect a variant, runtime type, or positional index: the concrete environment is monomorphized over the creator event, child occurrence, and compile-time path. The result of each attempted admission is an admitted receipt or the complete still-host-owned creation product, never a discarded ControlSender result.

Source action results

Creation uses the one generic action-settlement path, not the source-result protocol used by emitted requests. The same Driver operation must also process request items whose exact interpretation result returns to the emitting actor. Stable-proxy owner operations and direct-pool assignments are the first two unrelated request consumers.

Behavior supplies only static declarations and owned values:

  • the concrete action owns its accepted receipt, rejection, prerequisite, and source identity;
  • the generic source-action product fixes every returned input as the exact SettledItem<Item, ItemSettlement<...>> and preserves authored order;
  • ProxyOperation uses that exact result. Its accepted value is ProxyInputReceipt, containing the creator-local child route, exact proxy, and operation correlation; rejection retains the complete operation;
  • AssignmentDelivery uses the same exact result. Its accepted value contains exact worker and assignment correlation; rejection retains the complete assignment delivery;
  • PrepareWorkers uses the same start settlement for fixed supervision and direct-pool recovery. Its accepted value is an exact WorkerPreparationStarted receipt. The separately injected, later WorkerPreparation owns the source, ordered selected roles, complete prepared submissions or an exact worker/source rejection, and untouched suffix; and
  • structural composition processes inner then owned lanes, matching the one declared interpretation order.

An action may not choose another result type or translate the generic alternatives. Such a hook is a per-template settlement adapter: it can duplicate the interpretation law and can silently discard the exact rejected or unattempted action. Domain-specific receipts remain lawful as the accepted type; later domain outcomes and application replies remain separate protocols.

Those declarations perform no delivery. Bombay must add one generic static operation over the settlement products returned by CommitActions. For each source result, that operation must:

  1. retain ownership in the current actor host;
  2. construct the statically selected current-actor system input;
  3. submit it through the existing unbounded control capability;
  4. remove it from host custody only after control admission succeeds;
  5. recover the exact input from the returned closed-control event when admission fails; and
  6. after the first closed admission, transfer the current value and every later value without trying to reopen the actor.

The Driver processes one admitted result turn and the complete transitive action chain it produces before offering the next result from the earlier product. Only after that chain is quiescent or transferred outward may it continue with the next ordinary User communication. This must be an iterative queue owned by the existing Driver; it is not a recursive call, detached task, second mailbox, or second actor loop. The ordering does not claim termination or fairness: an actor can continually produce more source results and starve ordinary traffic.

SourceSettlementCustody::offer_next_to_source is the static operation over a complete ActionSettlement. It visits creation before sends, preserves every named field and wrapper order, and returns SourceCustody::Admitted immediately after exactly one successful admission. Exhausted proves no source input remains; Closed returns the current input and untouched suffix in the exact residual product. The operation composes through every generated named sends product, catalogue-owned named product, and SendLayer without Bombay matching product fields, variants, or structural positions by hand. The generic source product supplies the exact input type once. Neither FixedSupervisor, DynamicSupervisor, FIFO pool, nor keyed pool supplies a runtime admission adapter.

Exact Bombay and Timers changes for scheduling

Timer scheduling follows the same total action law; it is not a FixedSupervisor exception. ScheduleAfter currently declares the later TimerElapsed input but has no ActionItem settlement. The present Bombay interpreter computes Instant::now().checked_add(after) and returns only unit or DeadlineOverflow. The selected bombay-timers 0.1.0 queue replaces an existing equal key and panics when its internal generation or insertion sequence exhausts. Those are current implementation constraints to replace, not the architecture.

Behavior Actors must give both scheduling requests ordinary total contracts:

ScheduleAfter:
  accepted = TimerScheduled { id, generation }
  rejected = DeadlineOverflow
           | QueueGenerationExhausted
           | QueueSequenceExhausted

ScheduleAt:
  accepted = TimerScheduled { id, generation }
  rejected = QueueGenerationExhausted
           | QueueSequenceExhausted

The two rejection sums remain distinct because an already absolute ScheduleAt cannot incur relative-deadline overflow. Adding an impossible alternative merely to share a type is prohibited. Generic ItemSettlement already returns the complete original request for every rejection and preserves independent later lanes. TimerScheduled is only the exact scheduling receipt; the eventual TimerElapsed remains a later typed input and must never be fabricated at acceptance.

Timers must change its existing queue operation to return a closed error before changing counters, current-key state, or heap ownership. Bombay maps those two queue errors without collapsing them, maps relative deadline overflow only for ScheduleAfter, and returns the exact TimerScheduled receipt after insertion. The current queue token remains Timers-owned scheduling authority; a Behavior does not receive or recreate it. Poison recovery, memory exhaustion, and polling are not new Behavior rejection alternatives.

FixedSupervisor privately selects a non-reused timer identity for each delayed recovery and carries an explicit generation. Two overlapping delayed recoveries therefore cannot use the same queue key, because the selected queue truthfully treats equal keys as replacement. Immediate recovery emits no schedule and owns no dummy timer. Recovery identity, timer identity, and release ordinal stay distinct values; none is inferred from another or from product position.

Bombay implements these as the same generic static InterpretItem operations used by unrelated timing templates. It must not inspect FixedSupervisor, introduce a schedule adapter, create another timer queue, or return unit after successful scheduling. Its Driver settles scheduling in the named action order, admits the exact settlement through the normal source-result operation, and retains it through the existing retirement product if actor admission closes.

Exact Bombay changes for atomic diagnostics

Behavior Actors supplies one shared DiagnosticAction<Route, Diagnostic> for the identical diagnostic law used by FixedSupervisor, DynamicSupervisor, FifoPool, and KeyedPool. The action is exactly:

Deliver { route, diagnostic }
| Terminal { diagnostic }

The route type selects the real rejection vocabulary statically: Recipient<P> uses LogicalDeliveryReason, EstablishedRecipient<P> uses ExactDeliveryReason, and the route-free Infallible alternative uses Never. Bombay must add ordinary InterpretItem implementations for these three concrete route families. It must not switch on a runtime protocol, erase the diagnostic, or add an aggregate-specific interpreter.

For Deliver, Bombay consumes the route and diagnostic through the existing logical or exact delivery capability. Accepted delivery returns DiagnosticAccepted::Delivered. Rejection returns the complete original DiagnosticAction and the exact selected delivery reason. Waiting for bounded Communication capacity is backpressure and is not a rejection variant.

For Terminal, Bombay performs no delivery and returns DiagnosticAccepted::Terminal(diagnostic). The complete diagnostic therefore remains inside the accepted action settlement owned by the current actor host. When source admission is closed or the source stops in the same transition, that settlement follows the normal child-to-parent-to-root custody path and ends at the non-rejecting root custodian. Terminal transfer is not a log call, detached task, second mailbox, or special Driver branch.

The first production consumer is FixedSupervisor's exact non-ready initial proxy transition. It emits DiagnosticAction::Terminal(FixedDiagnostic::ProxyOutcomeFailed(...)) together with Step::Stop. Bombay must settle the diagnostic before completing actor retirement, retain the complete role/outcome payload, and then transfer the remaining proxy child graph through the same retirement barrier. The aggregate does not serialize that payload, log it as a substitute for custody, or keep a second runtime coordination object.

The next production consumer is FixedSupervisor's committed-roster shutdown. Its final Step::Stop retains the complete private FixedShutdown state. That state includes ready workers and readiness values, locally cancelled initial inputs, exact initial-input settlements, completed initial outcomes, proxy-stop results, rejected proxy births, and any non-accepted shutdown operation reunited with an exact proxy exit. Bombay must move that concrete stopped supervisor value through the same retirement product. It must not inspect those private alternatives, convert retained values to logs, or require FixedSupervisor to publish a runtime-specific residual. A pending proxy creation remains an ordinary previously emitted creation action: Bombay returns its exact generic settlement. FixedSupervisor alone decides whether that means one newly committed proxy must be shut down, an exact creation rejection means absence, or wrong provenance must be returned unchanged. Recovery and deadline shutdown states target this same generic retirement contract; they do not justify a supervisor-specific Driver branch.

H119 realizes FixedSupervisor's deadline half. The first RetireActorGraphAfter shutdown emits one ordinary relative scheduling action. Its exact non-accepted result or its exact elapsed timer selects Step::Stop; the private deadline state retains that exact cause while FixedShutdown retains every unresolved member value. Bombay must therefore transfer the final concrete supervisor and the environment's residual actions together. It must not inspect the deadline state, synthesize per-member shutdown reports, or discard the supervisor after extracting Exit or unit. The same generic retirement product also covers an external worker-source operation that is still resolving when the deadline forces retirement.

Bombay's required change is deliberately ignorant of FixedSupervisor's private decomposition. FixedShutdown decides declaration-order roster completion, FixedShutdownMember owns one member's remaining startup values, and ProxyStoppingMember decides the exact shutdown-settlement/exit join. Bombay only executes typed actions, returns their complete settlements, observes exact child exit, and transfers the stopped concrete behavior to parent then root custody. No in-memory supervisor coordinator belongs in Bombay.

CommitActions must preserve these receipts with every other item settlement. ActiveEnvironment::retire, the Driver retirement barrier, and the root runner must return or retain the terminal diagnostic exactly as specified by the general custody changes in this document. A delivered diagnostic rejection is already terminal settlement and must never be reintroduced into the aggregate to emit a recursive diagnostic.

Exact Bombay change for keyed customer rejection

AA-40 requires more custody than an ordinary reply delivery for one case only: a synchronously rejected submission must preserve the original customer route inside the rejected action while a clone targets the KeyedOutcome::Rejected message. Behavior Actors represents that invariant with the CustomerDelivery<P> action item. The public KeyedOutcome remains free of an address generic, and neither the key nor payload is cloned.

Bombay must add one generic static InterpretItem<CustomerDelivery<P>, ..> implementation alongside its existing logical and established delivery implementations. It exhaustively handles the four concrete alternatives:

Logical { delivery }
Established { delivery }
RejectedLogical { delivery, customer }
RejectedEstablished { delivery, customer }

The ordinary alternatives delegate to the corresponding existing logical or established delivery capability. The rejected alternatives do the same while holding customer untouched. Acceptance consumes the complete action and returns unit, matching ordinary delivery. Logical rejection reconstructs the same CustomerDelivery with the returned Delivery, original customer, and ReplyDelivery::Logical(reason); exact rejection does the corresponding operation with EstablishedDelivery and ReplyDelivery::Established(reason). Interpreter corruption likewise returns the complete reconstructed action and exact fault. The uninhabited delivery prerequisite remains uninhabited.

This is one generic customer-action interpreter, not a KeyedPool branch or settlement adapter. It does not inspect keys, roles, outcomes, bindings, pool state, or aggregate type. Bounded Communication send capacity remains backpressure. When actor admission is closed, the complete returned CustomerDelivery travels in the existing environment residual and parent-to-root custody path; the Driver must not reopen the stopped pool or discard the original route. The research-local Bombay probe must cover logical acceptance, logical rejection, exact acceptance, exact rejection, and source retirement after rejection using the unchanged Engine Driver.

The operation returns a residual product. A residual owns every result not admitted to the source, including the current result at closure and the exact untouched suffix. That product joins the environment retirement value described below. Bombay may not map it to a log, unit, a generic error, or a recreated request. The root runner is the final non-rejecting owner.

This is the required upstream change. The atomic worktree does not modify Bombay production source and does not add an in-memory coordination object to StableProxy or either supervisor. H34 demonstrates the stable-Rust ownership shape with distinct proxy and assignment results in both wrapper orders; the real Driver and retirement proof remains a Bombay integration gate.

H38 adds one exact interpreter obligation. Bombay's environment statically implements PrepareWorkers for the application's concrete method-free WorkerSource<Role, Worker, Plan> declaration. It invokes that source outside Behavior. H45 requires that action to expose each selected application role only as &Role: it owns immutable private role names while the pending supervisor state retains every unique member-role authority. Bombay must neither request Role: Clone nor reconstruct a role from roster position. It returns the same source authority and role names with every completed result. WorkerPreparation contains three late domain outcomes: a complete non-empty sequence of prepared submissions, an exact prepared prefix plus worker rejection and untouched suffix, or source rejection before the first worker submission. Corrupt or unattempted starts remain generic settlement alternatives; source rejection after an accepted start is a late outcome. The action is handled by the same InterpretItem and source-admission machinery used for proxy operations, assignment delivery, and unrelated catalogue actions. Bombay adds no dynamic registry, callback inside the actor, factory actor mailbox, erased worker envelope, or FixedSupervisor Driver branch. The result enters the same generic source-admission queue and retirement product described above.

The concrete static interpreter consumes the request with start() and returns its exact receipt before awaiting the source. It injects the later WorkerPreparation through the typed control lane. The returned StartingWorkerPreparation advances the first attempt with accept(submission), reject(reason), or reject_source(reason). Acceptance returns ControlFlow::Continue(PendingWorkerPreparation) while a selected name remains and ControlFlow::Break(WorkerPreparation) only after the last one. The initial request alone implements the action traits; the pending value cannot be re-emitted as fresh work after it owns a prepared prefix. This progression is the arity proof: Bombay never supplies a role to an accepted result and performs no separate length validation. If the Driver retires during preparation, its actor-owned source task retains the StartingWorkerPreparation or PendingWorkerPreparation value until it can return a complete result through exact typed retirement custody.

Every request also carries one private non-reused preparation ticket. Bombay must preserve it by moving the request, start receipt, and later result through the typed event paths; it must not inspect, construct, compare, log, or reconstruct the ticket. Exact matching is FixedSupervisor policy.

If shutdown overlaps an emitted preparation, Bombay must not report actor retirement merely because ordinary mailbox admission is closing. The started progress cursor remains in the actor-owned source task until interpretation produces its complete result. Open control admission returns that result to the draining FixedSupervisor; closed control admission moves it into typed retirement custody. In neither case may Bombay cancel the request, recreate its source, call a FixedSupervisor-specific adapter, or treat successful preparation as permission to issue replacement work. The aggregate owns that late-result decision.

The clean-room FixedSupervisor now realizes its half of this contract. Its shutdown member retains the private preparation expectation beside the exact StableProxy drain, and the stopped aggregate retains the complete generic result after admission. Bombay must therefore preserve the final monomorphized FixedSupervisor value when interpreting Step::Stop; extracting only a unit exit status would lose the source, rejection, prepared submissions, or interpreter fault held there. The required Bombay change remains the generic Driver retirement product described below. It is not a FixedSupervisor branch and does not require Bombay to know PreparationExpectation.

The FixedSupervisor's concrete internal event includes the typed start settlement and separate late preparation result but does not constrain the worker source in its unrelated proxy variants. PrepareWorkers<Source, Role, Worker, Plan> is the static source selector because that action type uniquely identifies its associated result. The named sends product includes one worker_preparations source-action lane. The generic source-admission operation injects the start settlement through EventIngress and the later result through InjectEvent; the Driver must not pattern-match FixedSupervisor, special-case the lane, or add a callback. The declared fixed-supervisor lane order places worker preparation after proxy creation/observation work and before proxy input, scheduling, lifecycle, reply, and diagnostic work. A later production slice must compile this exact product before automatic recovery is claimed.

FixedSupervisor proxy operations independently use Here as their static same-actor source. Bombay therefore admits their exact generic ProxyOperation<Here, Worker, Plan> result through ordinary EventIngress; the operation does not use the aggregate event type as a recursive selector. The worker-preparation result remains a distinct input type for that same current actor, with no positional routing or runtime lookup. Bombay's static generic admission implementation selects the actor through the action/result type pair; it does not inspect the action value or infer a runtime destination.

Direct pools use this same interpreter operation for automatic recovery with a non-empty sequence containing exactly one semantic role. The pool retains the recovery decision and role authority while the action owns the source and role name. Bombay gains no pool branch: the same static request progression returns the source, name, and one WorkerSubmission or the exact rejection. Initial pool construction remains separate and may invoke its factory before a Behavior exists. A pool never stores or calls that factory from a transition.

Engine retirement and root custody

ActiveEnvironment::retire, the local inbox drain, Driver, run_with, and the application result must carry one typed retirement product through the existing barrier. That product owns both the final monomorphized Behavior and the environment residual; it does not inspect or erase the Behavior. Parent rejection transfers the complete terminal value outward. The application root owns a non-rejecting custodian and releases the barrier only after that product is empty. This is the H03 contract as completed by H28's final-Behavior link, not a new service: retirement remains part of the same Driver future.

Required upstream verification

  • compile every concrete InterpretItem implementation without a universal error type;
  • replay H07 rejection, blocking, corruption, and wrapper-order suites against ApplicationCapabilities;
  • prove creation semantic rejection continues to an independent timer or delivery while only its exact child operation is blocked;
  • prove two heterogeneous creation alternatives return branch-preserving receipts and exact rejected requests;
  • prove ChildCreationSettled returns a non-cloneable child through one live creator and through closed creator admission into host custody, using the same generic code for an unrelated creating template;
  • prove stopping initialization settles final actions before publication or retirement;
  • inject control closure at every parent/root transfer and recover the exact value at the root custodian; and
  • run the unchanged single Engine Driver through the retirement barrier with no detached work and no ignored must-use result.

Stable proxy

Status: feature-complete for the local aggregate. Initial start, readiness, exact pre-ready return, replacement, owner shutdown, complete local custody, independent models, compile contracts, and two stateful fuzz targets are implemented and verified. Parent-to-root terminal transfer remains assigned to Bombay and does not belong in this aggregate. Actor-graph deadline policy belongs to the owning supervisor, pool, or Bombay root, not StableProxy. The complete transition matrix is owned only by actor-laws/proxy.md.

Responsibility

StableProxy owns one stable service identity and at most one current worker. It owns initial worker start, replacement, unavailability, exact worker exit, creation, initialization, activation, worker return, and structural-owner outcomes and diagnostics.

It does not own restart strategy, restart budgets, fixed membership, dynamic membership, pool jobs, customer outcomes, or runtime execution. Its public service protocol is exactly the worker protocol. Start, replace, and shutdown control remain private to the structural owner.

Fresh worker creation is the actor-model law. Stable service identity across successive workers is a derived proxy construction. Creation-before-dependent- operation ordering, owner-only control, activation admission, and lifecycle publication are Bombay policies.

One aggregate, separated concerns

StableProxy<W, P> is the only Behavior in this family. Its six files have one domain owner each:

  • mod.rs owns the aggregate, every state transition, construction, and the sole Behavior implementation;
  • state.rs passively owns the complete current and terminal state sums;
  • protocol.rs owns commands, events, outcomes, diagnostics, and returned terminal data;
  • effects.rs owns the seven named action lanes and their declared order;
  • operation.rs owns the parent request, receipt, rejection, and settlement contract;
  • worker/mod.rs owns the proxy's pending and current worker values, creation correlation, and shutdown/stop correlation.

The shared atomic/worker/initialization.rs and atomic/worker/activation.rs modules own the worker-host request and result protocol used by every atomic aggregate. They are not StableProxy child files. The pending proxy worker stores only creation and activation values; the emitted CreateChild owns the concrete worker until settlement, so no worker type marker exists in proxy state.

The worker module is not another actor aggregate. The worker's own Behavior owns its domain decisions; this module stores only the parent proxy's exact typed authority and observations. No transition verb or arrival path owns a file, and mod.rs controls the public surface. Fixed and dynamic supervisors consume typed proxy outcomes and must not reproduce worker creation, forwarding, readiness, replacement, or return transitions. Direct pools own a different direct-worker lifecycle and never consume proxy state.

Mnesis core was inspected as a DDD structure reference. Its useful pattern here is a flat, concept-owned kernel with one aggregate root and passive state. Its AggregateRoot, command dispatch, event replay, versioning, and persistence do not belong in StableProxy: the existing Behavior contract already owns the pure actor transition, and adding Mnesis would create a second aggregate model.

Current state and action law

The implemented closed phases are:

Dormant
Starting {
    Creating { stopped: Option<exact stop> }
  | Initializing { stopped: Option<exact stop> }
  | Activating { progress: WaitingForStart | Running, stopped: Option<exact stop> }
  | ReturningWorker(WorkerStopping)
}
Ready
EmptyInitial | EmptyAfter
Replacing { ReturningPredecessor | SuccessorResultAwaitingShutdown }
ShuttingDownCreation | ShuttingDownInitialization | ShuttingDownActivation
ShuttingDownWorker | ShuttingDownReplacement
Stopped(complete private retirement values)

H77 corrects the initial literal state lowering. Creation, initialization, and activation remain different phases, but each owns the same exact current truth: the correlated stop is absent or has arrived once. One Option<ChildStopped<_>> directly represents that invariant; separate *AfterStop phase and result sums would store arrival history and duplicate transitions. Activation separately owns WaitingForStart | Running. Its stop presence remains visible to the exact readiness transition, so stop-before-ready still cannot publish availability. No phase is represented by coordinated flags or several correlated optional fields.

An accepted start issues one checked CreationId, enters Creating, and emits the complete worker submission in CreateChild in that same transition. The proxy does not wait for a route result and stores no runtime nonce. Bombay either routes the complete creation batch or returns it unchanged with ChildNamespaceExhausted; the proxy then returns the complete worker and activation policy through generic creation settlement. A foreign or stale creation result cannot replace the pending submission.

Every staged worker creation emits one exact ObserveChild request in the same Actions. A committed worker emits one InitializeWorker request. Successful initialization returns the original activation plan and one non-cloneable ActivationPermit; only those values can construct BeginActivation. Bombay admits Started before polling the plan. Only a matching Ready received after matching Started opens service routing.

Readiness arriving before Started is returned unchanged as a diagnostic. A foreign worker, initialization, activation, shutdown result, or worker stop is also returned unchanged and cannot advance state. WorkerAttempt carries opaque issued evidence; its ordinal is diagnostic data and cannot prove identity. Two proxies' first attempts therefore remain distinct. Address reuse, timing, and adjacency prove nothing.

Service input in Ready becomes one EstablishedDelivery to the exact current worker. Service input in every other phase becomes one Unavailable owner outcome containing the original sender and command.

An initialization-effects rejection, activation-start rejection, or accepted activation rejection begins exact orderly shutdown of the committed worker. For initialization, Bombay retains the complete concrete action settlement in the worker environment and returns only the closed WorkerInitializationFailure classification plus the affine activation plan. The proxy reports the terminal owner result only after both shutdown resolution and exact worker stop arrive. Either arrival order retains all proxy-owned values. If the worker stopped earlier, later initialization or activation input consumes the stored exact stop without reopening service. If readiness arrives first, the worker becomes ready and a later stop follows the ordinary ready-worker law; H77 deliberately preserves this ordering distinction.

WorkerStartResult has three decisions: creation rejected, worker ready, or committed worker unavailable. WorkerCreationRejection owns the exact pre-commit cause. ProxyDrain<W, P> owns the exact committed-worker cause and retained values. The outer result never repeats those nested causes as another alternative. Its ready and unavailable alternatives carry the opaque worker attempt, not a worker actor or route.

ProxyDrain<W, P> is a visible ownership result. Its six alternatives name current worker outcomes: initialization rejected, stopped, or completed after an observed stop; and activation start rejected, activation rejected, or activation completed after an observed stop. A rejection that may follow an emitted worker-shutdown request owns Option of its exact shutdown receipt. None means no request was emitted because the worker had already stopped; it does not encode which transition function ran. Initialization-returned and observer-returned stops remain separately owned because they are independent authorities. There is no duplicate cause, forwarding constructor, projection operation, string case label, runtime lookup, callback, or generic policy. It never owns the worker's complete initialization action settlement. That runtime value follows Bombay's typed environment-retirement path. This keeps proxy and supervisor types independent of the worker's concrete send and birth products without erasing or discarding them. The unexpected-initialization diagnostic owns the complete WorkerInitializationReport<W, P> directly. That typed input exposes no runtime action product in ordinary application syntax and needs no second custody wrapper.

H124 normalizes all unexpected worker inputs to the same ownership equation. Each ProxyDiagnostic alternative owns the complete returned input and the copyable current ProxyPhase. The exact expected creation, worker attempt, initialization, activation, or shutdown authority remains solely in proxy state. It is neither cloned into the diagnostic nor moved out while correct admission is still possible.

ProxyPhase reports the current proxy work, not private stored-stop presence. Creating remains Creating and initializing remains Initializing after an exact early worker stop. The stop still participates in the later transition; the public projection cannot inspect or authorize it.

Replacement first issues the successor's checked creation ID while retaining its complete CreateChild value. The exact predecessor remains owned, stable service admission closes, and the proxy requests exact predecessor shutdown. If the creation sequence is exhausted, the complete successor returns and the ready worker remains unchanged. The retained creation is emitted only after the exact predecessor stop arrives.

Predecessor stop and shutdown settlement form an order-independent join. If the stop arrives first, one successor creation is staged immediately and the exact pending shutdown correlation remains with the replacement. If shutdown settles first, the complete prepared successor remains local until stop. A successor that becomes ready before the late predecessor settlement is retained and is not published early. Replacement from EmptyAfter needs no predecessor return and still uses a fresh creation ID and the same WorkerStart transitions. Overlap returns the complete submitted successor.

WorkerStart and ProxyReplacement are separate private closed state values. The former retains only creation-through-readiness or pre-ready return; the latter retains only proxy replacement values and the predecessor/successor join. Neither advances itself: StableProxy admits each event, selects the next aggregate state, and returns the complete Actions. Bombay continues to own namespace binding, actor creation, task execution, delivery of typed results, and terminal custody. No OCC store, lock, allocator, runtime handle, or second lifecycle service exists in the aggregate.

Both components consume the same private WorkerStopping transition. It owns only the exact shutdown-result/stop reunion and returns every unrelated input unchanged. It owns no start, replacement, supervisor, pool, or runtime policy.

Owner shutdown is total in every implemented live phase. It closes stable service admission immediately, emits no ordinary owner result, and never emits the same worker shutdown twice. An uncreated successor is returned through the existing replacement-cancellation outcome and is never created. Pending creation still settles because its worker has already moved into the emitted action. Initialization and activation results remain owned but cannot publish readiness.

Initialization and activation each retain only their own exact unfinished work and worker-return values during owner shutdown. They share WorkerStopping for the shutdown-result/stop reunion, but no generic outer return product: an initializing worker has no pending domain value corresponding to activation's real waiting/running value. Introducing a unit or marker merely to share that outer product is forbidden. A ready successor waiting for its predecessor result is returned before the proxy stops. Both the predecessor result and successor departure remain owned regardless of arrival order. A rejected or already stopped successor waits only for the predecessor result.

Initialization represents its returned work directly as Option<WorkerInitializationRetirement> while the worker departs. There is no parallel pending/returned enum: absence is the pending condition and presence owns the one complete returned value. A duplicate remains outside that option and is returned complete through diagnostics.

A stopped initialization is one outcome. Its optional initialization_stop owns a second stop returned by the initializer only when the enclosing stopped worker already owns the independently observed stop. Absence means the initializer's stop is already the enclosing worker stop. There is no StoppedAfterObservation alternative because that would preserve arrival order instead of current ownership.

Once the worker has stopped, each shutdown join stores one current product: the worker, the exact stop, the initialization or activation value still being awaited or returned, and Option<EstablishedShutdownResolved<_>>. A receipt is present only when the proxy emitted and settled a shutdown request; it is absent when the worker had already stopped and no request was emitted. There are no separate AfterDeparture, AfterStop, or terminal *AfterStop alternatives. Those labels described arrival history and did not change any later decision.

ProxyRetirement is not an application API or runtime service. It is the final private state of the concrete stopped StableProxy. Bombay must move that whole behavior together with its environment residual through the existing Driver retirement barrier, as specified in atomic-runtime-settlement.md.

Total interpretation

Actions::creates owns worker creation. ProxyEffects declares these send lanes in stable order:

worker observations
worker initializations
worker activations
worker shutdowns
worker deliveries
owner outcomes
diagnostics

Every runtime-local or structural-owner lane uses the one InterpreterRequests product. Worker service uses EstablishedDelivery. Actions still interprets child creation before these sends. A compile witness requires the concrete StableProxy::Sends, not a homogeneous stand-in, to implement the generic total interpretation contract.

The operation module also owns the crate-private receipt correlation evidence. Its tests prove that receipt consumption returns one affine operation id while the established proxy capability remains repeatable. FixedSupervisor has no parallel receipt model or fixture module.

No proxy-specific interpreter adapter exists. Corruption retains the committed prefix and exact untouched suffix under atomic-runtime-settlement.md.

Bombay realization

Bombay owns concrete child hosts, initialization action settlements, activation work, task retention, mailboxes, observation, and retirement. The exact single-Driver changes required for initialization, activation, parent/root custody, and retirement residuals are normative in atomic-runtime-settlement.md. Bombay production remains read-only in this campaign; no Behavior-side runtime substitute is permitted.

Verification and external integration

The local aggregate is feature-complete. Current verification supplies exhaustive small shutdown interleavings, independent models, generated longer sequences, two stateful fuzz targets, optimized replay, compile denials, and affine drop witnesses. The ready-worker target exercises exact and foreign shutdown inputs; the replacement target exercises overlap, cancellation, successor creation, and both predecessor-return orders. They share only the identical four-state worker-return join.

Bombay must supply the documented parent-to-root custody contract. The atomic implementation targets that contract without adding a Behavior-side runtime. This external integration requirement prevents a whole-system completion claim; it does not reopen StableProxy's locally owned transitions. The repository-wide gates are owned by atomic-actor-verification.md.

There is one canonical construction path described in atomic-actor-devx.md. No legacy With* wrapper, structural route, compatibility alias, public nonce, readiness flag, erased callback, or application-authored final behavior type may return.

StableProxy deliberately has no ActorDrainPolicy and schedules no deadline. The AA-01 law leaves deadline expiry and forced actor-graph retirement outside its implementation evidence. FixedSupervisor, DynamicSupervisor, FifoPool, and KeyedPool own their aggregate shutdown policies; Bombay root custody owns the remaining runtime transfer. Adding a proxy timer lane would take on another aggregate's responsibility and is prohibited.

Fixed supervisor

Status: active. The current implementation covers construction, startup, coordinated recovery, diagnostics, lifecycle publication, management queries, shutdown, and forced retirement. Four stateful fuzz targets cover shutdown, recovery, delayed release, and three-role recovery correlation. Remaining owner-partitioned viable mutation review, the local closure audit, the final repository gates, and Bombay root custody remain open.

The complete transition matrix is owned by actor-laws/fixed-supervisor.md. This document maps that law to the current Bombay Behavior design without repeating the matrix or its research history.

Responsibility

FixedSupervisor owns:

  • one non-empty ordered roster of unique application roles;
  • one StableProxy for each role;
  • each role's current membership and worker status;
  • activation capacity across unresolved proxy operations;
  • OneForOne, OneForAll, and RestForOne recovery selection;
  • restart eligibility, limits, release timing, and recovery correlation;
  • topology-failure disposition;
  • optional lifecycle publication;
  • operational diagnostics;
  • status and capability queries; and
  • complete actor-graph retirement.

It does not create or replace workers directly. StableProxy owns worker startup, replacement, service forwarding, and worker shutdown. The supervisor coordinates several stable proxies without copying that law.

It is neither a dynamic membership supervisor nor a pool. Its roster never gains a role after construction, contains no customer job, and is not selected by a mode flag shared with another aggregate.

Construction

fixed(...) is the sole construction path. Applications provide:

  • a function that prepares the initial WorkerSubmission for each role;
  • validated OrderedRoles;
  • ActivationPolicy;
  • Recovery;
  • FailureReaction;
  • ActorDrainPolicy; and
  • DiagnosticDisposition.

Lifecycle publication is the builder's only optional transformation. Every semantic policy is explicit; no no-op recipient or placeholder callback is required.

The initial worker function runs only while the builder prepares the roster. It is not stored in the resulting behavior and cannot run during a transition. Automatic recovery instead emits one typed PrepareWorkers action. Its exact settlement returns the worker source, prepared submissions, rejection, and untouched role names without an application callback inside the actor.

Construction either returns one supervisor owning every prepared role and submission, or returns FixedConstructionRejected. Its workers value is the shared InitialWorkerRejection: the function, accepted prefix, rejected role and reason, and unexamined suffix. The shared representation is owned by atomic-actor-architecture.md; this document owns only fixed-supervisor construction policy. A duplicate role is rejected by OrderedRoles before the supervisor exists.

Roster ownership

The roster preserves declaration order. Each role has one immutable roster position used only when the law observes order. The position is not an address, actor identity, or public path.

A role is owned by either an independent member or one admitted recovery. An admitted recovery owns a non-empty unique set of participating members and the stable position of its trigger. A member cannot occur in two recoveries. When a member returns to service it can leave the recovery independently; the recovery retires after its final participant leaves.

The current roster uses its existing ordered collections to answer selection, authorization, query, and shutdown-order questions. It does not keep parallel membership tables or before/after history.

Startup and activation capacity

Initialization emits one fresh StableProxy creation and one observation request for every declared role. Creation results are accepted only for the expected creation ID and kind. A rejected creation leaves that role without a proxy; a foreign or stale result is returned unchanged.

ActivationPolicy limits unresolved proxy operations, not actor count. The supervisor authorizes waiting roles in declaration order while capacity exists. An exact accepted proxy-operation settlement is required before the matching proxy outcome is admissible. Capacity is released when the admitted outcome resolves, even if another member value still awaits its matching stop.

A ready outcome makes the member available through its stable proxy. A failed startup follows the configured diagnostic disposition and topology reaction. Stopping the complete supervisor reuses ordinary supervisor shutdown; retiring one member reuses that member's exact proxy retirement.

Worker-stop classification and recovery selection

Recovery policy classifies an exact worker stop:

  • Temporary never starts automatic recovery;
  • Transient recovers only after an abnormal stop; and
  • Permanent recovers after every exact stop.

An ineligible stop leaves the member empty. An eligible stop selects members by strategy:

  • OneForOne selects only the stopped role;
  • OneForAll selects the complete eligible roster; and
  • RestForOne selects the stopped role and eligible roles declared after it.

Normal or abnormal classification is derived from the exact owned worker stop at this decision. The accepted stop does not retain a second classification that could disagree with the terminal outcome.

Selection is all-or-nothing. If a required role cannot participate, the unchanged roster is restored and the configured topology response is applied. Disjoint recoveries may coexist, but their role sets may not overlap.

One accepted selection moves the sole WorkerSource into one PrepareWorkers action. The supervisor retains the exact recovery correlation and cannot issue replacement work until the source result returns. The action's accepted start receipt establishes only that source work began. A later prepared result pairs each selected role with exactly one WorkerSubmission in declaration order. Worker or source rejection is a late typed result; interpreter corruption and no-attempt return the original request in the start settlement.

The worker source has one private custody sum: it is available to the supervisor, owned by one emitted worker preparation, or retained as that complete returned preparation while the supervisor retires. There is no parallel optional return field. A shutdown return changes custody only; it cannot reopen recovery or issue another preparation.

Restart admission and release

Returned prepared workers are not yet authorized replacements. In the same actor transition that accepts the exact preparation result, the supervisor carries every prepared worker directly into one restart-admission transaction. It does not store a separately observable prepared roster phase. The transaction combines:

  • its checked lifetime recovery count;
  • the inclusive restart window and maximum;
  • checked release calculation;
  • one non-reused recovery ID; and
  • for delayed release, one non-reused timer ID and generation.

RestartLimit owns the inclusive window and maximum. RestartRelease owns the release calculation.

The transaction commits all of those values together or returns them unchanged. It cannot partially spend a count, history entry, recovery ID, or timer key. Its six denial alternatives are stored once in RecoveryDenialReason; recovery admission moves that value and the complete triggering worker stop into RecoveryDenied, which exposes both by reference without rebuilding a parallel diagnostic sum. Denied prepared workers remain in the topology response selected by FailureReaction; admitted workers become one durable recovery batch. Timer schedule rejection does not use this stop transfer: its diagnostic owns the rejected timer request while topology retains the worker stop.

The requested replacement count retains the native non-empty roster cardinality. Only an accepted budget charge is narrowed to the configured u32 limit, so an oversized coordinated recovery is reported as an unchanged restart-limit denial rather than internal corruption.

Release policies are:

  • immediate;
  • constant delay;
  • linear delay, initial × ordinal; and
  • exponential delay, initial × 2^(ordinal - 1).

Arithmetic is checked before applying the configured maximum. Overflow is a typed denial, never saturation or panic. Delayed release emits the generic ScheduleAfter action. Only its exact accepted timer may later authorize the recovery; rejected, stale, foreign, early, or duplicate timer inputs cannot.

Replacement progress

Each participating member keeps its stable proxy and one current replacement product. That product owns:

  • the previous worker attempt and readiness;
  • the exact predecessor stop, if it has arrived; and
  • the current proxy response: input pending, outcome pending, returned outcome, or rejected input.

The exact input settlement, predecessor stop, and proxy outcome update only their corresponding value. The accepted input settlement must precede the proxy outcome. After that admission, predecessor stop and proxy outcome may arrive in either order and produce the same restart. Duplicate, stale, early, or foreign inputs return unchanged.

Successful readiness returns the member to service and publishes lifecycle events in semantic order. Input rejection or proxy failure preserves the complete diagnostic payload and enters member retirement or supervisor shutdown according to policy. The next waiting member may use released activation capacity even while an earlier predecessor stop remains outstanding.

Diagnostics and lifecycle publication

DiagnosticDisposition has two exhaustive choices:

  • DeliverTo attempts one typed diagnostic delivery; or
  • Terminate transfers the diagnostic with the stopped behavior.

FixedDiagnostic distinguishes startup failure, proxy-input rejection, worker preparation failure, restart denial, restart scheduling failure, unavailable service work, and unexpected typed input. Unexpected input retains the complete input while the unchanged supervisor retains every expected correlation. Terminal startup failure likewise leaves every unrelated roster member inside the stopped supervisor; only Bombay's generic retirement transfer may move that remaining ownership outward.

A preparation failure is valid for every recovery strategy and selected roster size. Non-trigger participants return to their exact prior member states; the trigger remains stopped. The diagnostic retains the prepared prefix, exact rejection or interpreter disposition, and untouched suffix, while the supervisor separately retains the reusable worker source and applies FailureReaction.

FailureReaction is independent of diagnostic delivery:

  • RetireMember removes only the unavailable role; or
  • StopSupervisor retires the complete supervisor.

Optional FixedLifecycle publication reports started and restarted workers, ineligible and admitted worker stops, unavailable service commands, and member retirement. When no lifecycle recipient is configured, no lifecycle value is constructed. Lifecycle publication never replaces the operational diagnostic that owns a failure cause.

Management protocol

The public FixedCommand protocol contains:

  • Status, returning every member status in declaration order;
  • Capability, returning the stable service capability for one role or the exact unavailable/unknown-role result; and
  • Shutdown.

Queries do not copy or change roster ownership. They remain admissible while the supervisor is operating or draining. Only a ready member yields a service capability; startup, empty, recovering, stopping, and retired members return the corresponding UnavailablePhase.

Service commands use the stable proxy. If the proxy has no ready worker, the supervisor accepts the exact returned command only while that proxy is still a live member. The command is then moved to either the configured lifecycle publication or WorkerUnavailable diagnostic. It is never stored as roster state.

Shutdown and retirement

The first shutdown closes recovery admission and projects every live member in declaration order. It emits at most one shutdown operation for each live stable proxy. Repeated shutdown emits none.

Each proxy retirement is a commutative join of its exact shutdown-operation result and exact proxy exit. Either may arrive first; neither alone retires the member. A rejected operation remains complete. A member already stopping is adopted without issuing a duplicate operation.

Other work already outside the actor remains required during shutdown:

  • proxy creation results;
  • initial and replacement proxy-operation settlements;
  • proxy outcomes and worker stops;
  • worker-preparation start settlements and later source results; and
  • restart-schedule settlements and exact elapsed timers.

Late results may restore custody or finish retirement but may not reopen recovery or issue replacement work.

WaitForActorGraph waits for every owned proxy to retire. RetireActorGraphAfter also emits one exact deadline schedule. Its accepted timer, or an exact schedule rejection/no-attempt/corruption, selects forced retirement while preserving the complete unresolved supervisor and exact cause. Foreign, stale, early, and duplicate deadline inputs return unchanged.

The stopped value retains every worker, submission, operation, result, stop, timer request, and diagnostic still owned by the supervisor. Logging is not custody, and Behavior does not spawn a task to dispose of those values. Because retirement consumes or drops that complete value instead of inspecting each private field in the producing crate, the corresponding fields carry checked dead-code expectations. Replacing them with unit is forbidden by the drop-count ownership regressions.

Bombay collaboration

Behavior owns the pure transition and complete Actions. Bombay must:

  1. interpret the named action lanes in declared order;
  2. return every exact accepted, rejected, blocked, corrupt, or unattempted item;
  3. admit initialization actions before ordinary ingress;
  4. move the complete stopped supervisor into parent/root retirement custody;
  5. keep accepting settlements through that retirement path without reopening the stopped actor; and
  6. use the existing Engine driver and retirement barrier.

The required Bombay change is specified in atomic-runtime-settlement.md. It is an upstream composition requirement, not permission to add a FixedSupervisor-specific driver, detached task, mailbox, settlement adapter, or callback.

Canonical construction and application syntax are owned by atomic-actor-devx.md. Verification ownership is mapped in atomic-actor-verification.md.

Dynamic supervisor

Status: feature-complete locally. DynamicSupervisor implements bounded keyed services, all five management commands, replacement, unexpected worker exit, lifecycle and diagnostic publication, shutdown, and forced retirement. Focused unit and model evidence plus four stateful fuzz targets cover cancellation, transferred cancellation, shutdown, and unexpected exit. Three viable mutation partitions have no survivors, direct construction inference and authority forgery have compile contracts, and the obsolete legacy supervision corpus is gone. Final fresh campaign audits and Bombay root custody remain open.

The complete transition law and exhaustive input matrix have one owner: actor-laws/dynamic-supervisor.md. This document is the shorter component guide.

Responsibility

DynamicSupervisor owns a bounded keyed service table; a fresh non-reused generation for every accepted start or semantic rebind; start, replace, stop, query, and cancel commands; exact operation correlation and affine cancellation authority; overlap rejection; lifecycle and diagnostic publication; unexpected worker-exit policy; capacity release; and complete shutdown or forced retirement.

It delegates stable forwarding and worker replacement to the single StableProxy implementation. It owns no fixed roster, coordinated restart strategy, restart budget, worker factory, pool queue, customer outcome, runtime task, mailbox, address allocation, or actor loop. It is not a configurable FixedSupervisor.

Fresh proxy and worker allocation follows the actor-model freshness law. The keyed table, generation policy, operation correlations, phase-sensitive cancellation, bounded terminal-operation retention, and durable lifecycle reporting are Bombay policies.

Construction

The canonical constructor is:

dynamic(
    entries,
    activation,
    unexpected_exit,
    actor_drain,
    lifecycle,
    diagnostics,
)

entries is a validated EntryCapacity; activation is a validated ActivationPolicy. Both have checked constructors from usize, return ZeroCapacity for zero, and cannot be exchanged accidentally. Every other argument is a distinct required policy or typed capability. There is no default, callback, marker, empty route, structural path, application alias, or public proxy factory.

The complete application syntax and public products are owned by atomic-actor-devx.md.

Commands and outcomes

The application protocol has exactly five commands:

  • Start admits a new key and complete worker submission;
  • Replace changes the worker behind an existing stable service;
  • Stop drains and removes one ready, empty, creating, or waiting service;
  • Query returns the current public service projection; and
  • Cancel uses the exact affine authority returned by an accepted start or replacement.

Start and replace share WorkerChangeReceipt and WorkerChangeRejection<Reason> because their accepted and rejected ownership is identical; their reason sums remain distinct. Stop, query, and cancellation keep their own result sums because their outcomes and retained values differ. DynamicLifecycle owns durable later outcomes. DynamicDiagnostic owns malformed, stale, contradictory, or rejected runtime input according to the configured disposition.

If global shutdown arrives while proxy creation is unresolved, the entry keeps one of two private current phases: supervisor shutdown, or drain of an already admitted explicit Stop. Both are publicly Draining, but later creation settlement preserves their different terminal lifecycle outcomes. No optional stop marker or repeated operation correlation encodes that distinction.

Service and cancellation rules

An accepted start reserves one fresh entry generation, proxy creation ID, ordered management operation, and cancellation authority before committing the entry. The management-operation order also determines which waiting service receives the next activation authorization. The table itself is the source of that ordering and capacity use; there is no second queue or occupancy flag. The affine cancellation authority owns the key and this globally non-reused operation. Entry generation remains lifecycle identity rather than a duplicate cancellation coordinate.

Cancellation returns a worker submission only while the supervisor still owns it locally. After transfer to the proxy, cancellation is logical: the worker is not reconstructed or returned, and a later successful proxy report cannot publish Started or Replaced. The supervisor retains the exact worker result, proxy-shutdown result, and proxy exit until all three resolve. Only then does it publish OperationCancelled and EntryRetired(Cancellation), remove the entry, and release entry capacity. Private proxy-input custody names input rejection and a later proxy report as distinct terminal outcomes; rejection is never encoded as an absent report. Cancellation completion constructs the ordered OperationCancelled then EntryRetired(Cancellation) pair as one closed domain operation; callers cannot select another retirement cause or omit either message. The aggregate selects the exact entry once from the creation carried by the proxy input result; retirement custody does not accept or repeat that correlation. Arrival order does not change the result.

One matching terminal cancellation record is retained until the next accepted change. This makes immediate replay truthful without an unbounded history. Once the entry retires or its key is rebound, the old authority is stale. A rebound key always receives a fresh generation.

Replacement does not copy StableProxy's predecessor-drain logic. StableProxy reports replacement only after its own predecessor has drained. The supervisor validates that report against the retained current service and stores the exact successor or typed unavailability outcome.

Explicit stop and automatic unexpected-exit retirement remain different operations. Its terminal failure is one shutdown-settlement reason together with zero or one exact proxy stop. Those values are independent: the reason is reported unchanged, while stop absence permits restoration and stop presence requires retirement. The representation stores neither arrival order nor four copies of the same optional stop. Stale, duplicate, foreign, wrong-generation, and wrong-operation inputs return or diagnose their complete values without mutating the current entry. Proxy input and exit select their exact entry once; phase transitions do not repeat that same creation comparison or expose an unreachable second wrong-proxy failure.

Shutdown

Global shutdown arrives through the existing typed ShutdownRequested control event; it is not a sixth application command. The supervisor closes new mutations, converts every retained entry exactly once, preserves each unfinished worker change, and drains according to ActorDrainPolicy.

WaitForActorGraph waits for every entry. RetireActorGraphAfter schedules one deadline and stops after its exact timer or scheduling rejection while retaining the unresolved supervisor state for runtime custody. Behavior Actors creates no second Driver, mailbox, task, registry, or shutdown service.

Bombay collaboration

Bombay must assemble applications role-first: establish lifecycle and diagnostic actors, supply their typed capabilities to one pure root construction, and only then activate the root. DynamicSupervisor stores those capabilities; it never looks them up or creates them through an application callback.

Bombay must also carry stopped-child output through parent admission to a non-rejecting root custodian and its existing retirement barrier. The required Engine and custody changes are specified in atomic-runtime-settlement.md. They are runtime composition work, not DynamicSupervisor behavior or a reason to adapt this aggregate to Bombay's current limitations.

Verification

Current evidence covers admission and overlap, cancellation replay and stale authority, pre- and post-transfer cancellation, all six worker/shutdown/exit orders, retained capacity, fresh same-key reuse, replacement, explicit stop, unexpected exit, repeated shutdown, forced residual transfer, and complete named action lanes. Four dedicated fuzz targets each pass 4,096-input replays in development and optimized profiles. Direct real construction infers without a final aggregate type, and compile-fail contracts reject duplicated or forged cancellation authority. Same-signature foreign authority remains AA-20's runtime-stale case rather than a fabricated compiler-only owner brand. The verification plan and remaining whole-catalogue gates are owned by atomic-actor-verification.md.

FIFO pool

Status: feature-complete for the local aggregate; final whole-catalogue audits and Bombay root custody remain. Ordered dispatch, assignment reunion, direct-worker start/activation, recovery eligibility, role retirement, and dispatch shutdown custody have focused models and production tests. Complete worker-source settlement, immediate and delayed replacement release, restart-limit denial, topology disposition, and exact restart schedule/timer correlation now have focused production tests. Exact operating stops before readiness and their returned initialization/activation values now have focused production tests without another worker state machine. Standalone pre-ready failures now stop their installed worker and wait for the exact shutdown/exit reunion before recovery. Late activation results during drain advance only the exact existing progress and never restore eligibility. Restart schedules outside the actor remain pending through drain; accepted restart timers transfer their cancelled replacement immediately. Orderly retirement releases the drained roster, while forced retirement retains the unchanged unresolved roster and exact cause in the final concrete behavior. Generated operating and FIFO-only fuzz evidence now exist. The canonical worker and direct-construction compile contract, two actual timer-wrapper orders, six focused compile denials, and result-type inversion are retained. The warning-custody audit, complete viable mutation audit, and replacement performance baseline are retained. The complete FIFO suite passes 90/90 in debug and optimized modes. Its 305-candidate mutation run has 118 caught, 187 unviable, zero surviving, and zero timed-out candidates without exclusions. The optimized canonical fixture sustains a median 2,732,844 complete assignment cycles/s across five 100,000-cycle runs; this is pure aggregate throughput, not mailbox or Engine throughput. Bombay owns the documented terminal-custody change. The complete transition law is owned only by actor-laws/fifo-pool.md.

A test-only independent customer desk now compares the production aggregate's public customer actions after every input in all 24 permutations of assignment delivery acceptance, completion, exact worker exit, and shutdown. Its oldest-observation queue independently predicts first-terminal precedence, route and payload custody, shutdown return, and terminal uniqueness. It reads no private aggregate state. Recovery and full-drain sequence parity are closed by the direct independent comparisons below. An independent recovery desk also matches all 20 combinations of operating or shutdown ownership, both topology reactions, and every preparation outcome. An independent retirement desk matches every ordering of one ready worker's stop, shutdown return, deadline rejection, accepted scheduling, and exact deadline firing. It proves normal role release and forced role retention without reading private pool state. A generated queue desk additionally compares 192 shrinkable scripts of up to 128 repeated submissions, delivery acceptances, and completions against the real aggregate after every applicable input. Its sole VecDeque predicts bounded admission and oldest-first dispatch without reading private pool state; a newest-first inversion fails on the exact next payload. The FIFO-only fuzz target retains the real emitted assignment plus concrete stale and foreign inputs. It discovered and now preserves both exact worker-stop orders in which accepted or rejected delivery settlement reunites the final assignment prerequisite. Three named seeds, 5,000 development runs, and 5,000 optimized runs preserve terminal uniqueness and every unrelated action lane without importing a private pool phase.

Responsibility

FifoPool owns direct worker incarnations, one bounded global backlog, immutable admission order, direct assignment authority, completion correlation, worker interruption, at-least-once retry or exact failure return, direct-worker restart policy, exactly one terminal customer outcome per accepted job, and complete shutdown extraction and drain.

It contains no stable proxy or hidden supervisor. It owns no key, binding, per-role queue, affinity selector, or keyed management operation. It is not a mode of KeyedPool.

Collaboration and policy

Fresh worker allocation is the actor-model law. FIFO admission, circular idle selection, immutable retry ordering, interruption disposition, restart policy, and terminal customer custody are Bombay pool constructions. Assignment and direct-worker lifecycle values may be shared with KeyedPool only after the same law suite passes both consumers without modes, ignored outcomes, or weaker errors.

The pool retains the canonical customer obligation and route. A worker receives only a moved assignment containing execution payload and affine completion authority. Delivery settlement, completion, and exact worker exit form the four-way order-independent join owned by the aggregate; a generic settlement lane cannot replace it.

A queued obligation stores only its immutable admission order and an optional assigned role. The role remains necessary for a later assigned-job return. The event that caused retry does not remain in queue state because worker exit and rejected delivery have identical future behavior. Forced-retirement and emitted diagnostic payloads are different: they remain complete affine custody until Bombay or the selected diagnostic route accepts them.

Exact worker shutdown reuses the generic protocol described in atomic-runtime-settlement.md: the lifecycle host retains the complete ActionItemResult<ShutdownEstablished<...>>, while the pool later receives only EstablishedShutdownResolved<P> and the exact ChildStopped input. Direct-worker state must not duplicate the emitted request or import StableProxy's private worker state.

The initial factory is consumed only while constructing the all-or-none roster. Its rejection is the shared InitialWorkerRejection described in atomic-actor-architecture.md, embedded in FifoConstructionRejected beside FIFO policy. Automatic recovery never calls that closure inside Behavior; permanent and transient recovery emit the generic typed worker-source request for one role, which Bombay executes and settles outside the actor. Temporary recovery has no source. One shared worker classification defines normal and abnormal stops for both fixed supervision and FIFO. FIFO then owns the closed decision to prepare, wait while its single affine source is in use, retire the role, or stop the pool. A second simultaneous eligible stop cannot duplicate the source and waits in declaration order. FIFO still owns budget, timing, and topology disposition. An exact preparation start receipt records that the source has begun; it does not assert a prepared worker. The later successful, worker-rejected, or source-rejected result returns the affine source exactly once. A corrupt or unattempted start returns the original request. Under RetireRole, that source immediately serves the first waiting role before ordinary dispatch; under StopPool, ordinary shutdown drains surviving workers. Delayed restart release admits only its exact schedule result and timer once. When an exact temporary worker stop becomes actionable, RetireRole removes that role from future dispatch, fills any surviving ready worker from the same ordered backlog, and returns the remaining backlog only when no serviceable or recoverable role remains. StopPool enters the ordinary pool shutdown path and requests shutdown only from workers that have not already stopped. A temporary worker never occupies recovery state.

An exact initialization or activation failure without a prior stop does not retire an installed worker by assertion. The pool transfers the complete returned failure through diagnostics, requests exact worker shutdown, and reuses the same Stopping shutdown/exit reunion as rejected assignment delivery. Activation failure releases its occupied capacity and admits the next waiting role in declaration order. Recovery begins only after both shutdown settlement and exact worker exit arrive.

Once pool shutdown begins, an activation already dispatched remains correlated until its exact result returns. Exact Started advances that worker from dispatched to activating. Duplicate or foreign starts are diagnostic-only. A later readiness or rejection retires the activation progress into diagnostics; it cannot make the worker idle, assign queued work, or start recovery. The same worker remains in the ordinary exact shutdown/exit reunion.

FIFO and KeyedPool implement that retirement equation once in the direct-worker model. Retirement stores Option<WorkerStartupCustody>: an inhabited value is the exact activation plan, initialization attempt, activation permit, activation start, or activation still owned locally; absence means no startup value remains. It does not use service readiness to stand for absence. The shared transition admits only exact initialization and activation inputs and returns complete foreign, duplicate, rejected, or late values for aggregate diagnostics. Queue, customer, binding, recovery, deadline, and final actor policy remain outside it.

A worker creation emitted before shutdown remains admissible during drain. If the exact actor is established after admission closes, FIFO starts no worker initialization or activation work: it emits one exact shutdown and holds the activation value in the drain member until exact stop. If that stop was already observed, FIFO retires the member immediately and transfers the activation to diagnostic custody. Rejected creation transfers the returned worker, activation, and any prior stop together. Foreign or reversed creation results leave every pending member unchanged.

An emitted worker-preparation request remains pending after shutdown even when all direct workers have retired. Its exact start settlement and, if started, later source result have distinct correlation phases. Only its private exact ticket can release that drain member. The late successful, worker-rejected, or source-rejected result restores the affine source when valid and transfers every cancelled submission, rejection, and stopped-worker value to diagnostics. It cannot create a replacement or emit a restart schedule. A foreign return leaves the member unchanged, and normal pool retirement waits for the exact return. Corrupt or unattempted starts return the original request before source work begins.

An emitted restart schedule likewise remains pending until its exact accepted, rejected, corrupt, or unattempted return. Shutdown then transfers the stopped worker, uncommitted replacement, and schedule return to diagnostics without creating another worker. A foreign schedule cannot release that custody. Once Timers accepts the schedule, Timers alone owns whether an elapsed event will be published; pool shutdown immediately transfers the cancelled replacement and does not wait for that event. Any later elapsed event is stale input. Worker restart and actor-drain schedules use distinct identities and cannot settle one another.

Normal retirement is the payload-free Stopped alternative; it retains no role or shutdown history. Shutdown-identifier exhaustion, an exact returned deadline schedule, or exact deadline firing instead enters the private ForcedRetirement alternative. That alternative owns the unchanged ordered drain roster and the exact cause. It does not reinterpret unresolved worker creation, activation, assignment, recovery, or shutdown values as completed. Bombay moves the whole final concrete behavior together with its environment residual through the existing Driver retirement barrier. FIFO adds no residual action lane, runtime adapter, actor loop, or task. Work still outside the actor, including an accepted activation or worker-source request, remains in Bombay's environment residual rather than being duplicated inside the pool.

Realization gate

Canonical construction, submission, outcomes, and the required assignment.complete(result) worker expression are owned by atomic-actor-devx.md. The implementation must prove capacity zero/full boundaries, FIFO fill, multiple interrupted reinsertion, every assignment join order, authority reunion, duplicate/stale/foreign completion, recovery, complete shutdown, and exactly one terminal outcome.

No supervisor, proxy, generic pool engine, selector placeholder, structural parent route, named interpreter send lane, helper type alias, or alternate pool spelling may survive. Repository-wide verification status and remaining gates are owned by atomic-actor-verification.md.

Keyed pool

Status: feature-complete locally. The aggregate implementation and both bounded independent models are executable. Separate retained stateful targets isolate binding management from assignment/retirement custody. The assignment/quarantine partition has all 18 viable candidates caught, including exact nonzero-role completion selection; the binding value/table partition has all 22 viable candidates caught, including public evidence privacy and exact caller request identity. The recovery partition has all 13 viable candidates caught, including exact delayed recovery of a nonzero role through preparation, scheduling, and timer release. The binding and recovery partitions retain 49 and twelve compiler-unviable substitutions as inventory only. The shutdown partition has both viable candidates caught; thirteen compiler-unviable defaults remain inventory only. The complete fresh 232-candidate owner inventory is classified: all 72 executable candidates are caught and 160 compiler-unviable substitutions remain inventory only. Final campaign audits and Bombay root custody remain open.

Production includes canonical construction, pre-ready admission, generation-exact binding management, exact successful direct-worker startup, role-local dispatch, both accepted-delivery/completion orders, foreign completion rejection, exact busy-worker interruption, permanent role extraction, rejected-delivery authority reunion, worker quarantine, direct worker preparation, immediate and delayed replacement release, exact restart schedule/timer correlation, and shutdown custody for creating, initializing, waiting for activation capacity, activating, ready, busy, quarantined, waiting for the recovery source, preparing, scheduling a restart, and waiting for its timer. An unused activation plan remains in the terminal diagnostic action until the interpreter settles that action; it is not destroyed when the worker exits. Forced retirement retains the unchanged unresolved worker roster and exact cause in the final concrete behavior; a non-cloneable pending worker value proves that custody survives Step::Stop. Generic settlement and FIFO's complete direct-worker consumer are retained, and Bombay owns the documented transfer of final behavior and actions through its retirement barrier. The private diagnostic-cause sum carries a checked dead-code expectation because the selected custodian receives it intact; KeyedPool does not expose lifecycle internals merely to make the producer inspect them. The complete transition law is owned only by actor-laws/keyed-pool.md.

Responsibility

KeyedPool owns direct workers, one bounded queue per semantic role, stable future-admission affinity, bounded bindings, non-reused binding generations, exact generation-or-current-absence management expectations, rebalance/unbind, assignment and completion, permanent role retirement/binding removal, exactly one terminal customer outcome per accepted job, and complete shutdown drain.

It has no global FIFO queue, circular selector, stable proxy, or supervisor. It is neither a wrapper nor mode of FifoPool.

Collaboration and policy

Fresh worker allocation is the actor-model law. Concrete key selection, binding capacity, fresh global generation, same-role rebalance semantics, immutable admitted affinity, per-role admission, and automatic binding extraction are deliberate keyed-pool policies.

The binding table solely owns each retained key. Accepted work retains only opaque generation/role evidence and its immutable admitted role. Unbind or rebalance affects future admission; it cannot retarget queued, assigned, or retried work. Permanent role unavailability removes every binding and returns all role-owned work in one transition. Temporary recovery retains bindings.

The initial factory is construction-only. KeyedConstructionRejected embeds the shared InitialWorkerRejection described in atomic-actor-architecture.md beside keyed policy. Permanent and transient recovery use the same generic one-role worker-source request as FIFO and fixed supervision; Bombay executes it outside Behavior, while KeyedPool owns eligibility, budget, timing, binding consequences, and topology disposition. Temporary recovery has no worker source.

FIFO and KeyedPool use one passive direct-worker component for successful child creation, initialization, activation admission, and readiness. That component cannot inspect a queue or binding and cannot emit Actions. KeyedPool alone selects the correlated role, applies the global activation capacity, and drains only that role's oldest queued job when its worker becomes ready. Creation identity and lifecycle kind are selected once by the shared ordered mapping; the member transition does not repeat that correlation test.

They also use one direct-worker retirement transition. Its Option<WorkerStartupCustody> owns only a concrete startup value still local to the pool; absence means none remains. An exact stopped initialization joins the authoritative worker stop with shutdown and returns the unused activation plan. An exact activation Started receipt advances the retained attempt without a diagnostic; a later terminal or duplicate activation remains complete for the owning pool's diagnostics. This component chooses no binding, queue, customer, deadline, recovery, or final actor outcome.

FIFO and KeyedPool now also consume the same private AssignedJob join. A completion received before its delivery receipt remains attached to the assignment; the exact receipt releases one customer completion. When the receipt arrives first, the exact completion releases that outcome directly. Worker identity alone is insufficient: the completion authority must identify the retained assignment. An exact worker stop applies the configured interruption policy once. If retry is selected but recovery retires the role, the job remains an assigned obligation and is returned as RolePermanentlyUnavailable; it is never reclassified as queued. Role retirement extracts that role's queue and every binding in the same aggregate transition.

FIFO and KeyedPool also use one private ForcedRetirementCause: exhausted worker-shutdown identifiers, a deadline that was not scheduled with its complete interpreter result, or the exact elapsed deadline. Each pool still owns its own unresolved workers, customer extraction, and terminal transition; there is no common pool or retirement engine.

FIFO and KeyedPool consume the same exact preparation start settlement and later source-result law. The shared worker value correlates the exact preparation request through both phases, retains the stopped worker and complete replacement submission, and changes from waiting for schedule acceptance to waiting for the exact timer. It cannot choose a role, touch a queue or binding, apply a failure policy, emit an action, or create a worker. KeyedPool alone serializes its affine recovery source, applies restart limits and release timing, returns work, removes bindings when a role becomes permanently unavailable, and selects role retirement or pool shutdown.

Rejected delivery returns the complete assignment to the shared authority reunion. An exact return restores the existing customer obligation to its original role queue at its immutable admission order, then quarantines that worker. The role remains unavailable until both the shutdown response and the exact worker exit arrive in either order. Only then may recovery or permanent role retirement begin. A returned assignment that contradicts an already received completion returns the customer obligation once, preserves both contradictory inputs in diagnostics, and drains the pool.

The independent keyed_model checks two keys/roles, zero and one capacities, all eligibility classes, exact management expectations, immutable affinity, every delivery/completion/stop permutation, retry order, retirement, shutdown, 22,621 bounded prefixes, and five deliberate inversions in debug and optimized builds. The production keyed_binding_sequences fuzz target separately drives only management commands through the real aggregate. Its scenario stores one absent-or-bound value, issued and stale generations, and one foreign generation; it owns no assignment, customer, or worker-retirement state. Five thousand development and five thousand optimized inputs preserve same-role stability, role-changing and post-unbind freshness, exact stale rejection, and foreign generation rejection.

The separate keyed_assignment_sequences target begins with one ready worker and one accepted binding, then drives accepted or rejected delivery, completion, exact and foreign stops, shutdown settlement, and replay. Five thousand development and five thousand optimized sequences preserve the original job, payload or result, role, generation, logical customer, and one terminal outcome. Its model retains the current post-stop phase because a late receipt can release terminal custody, and permits ReturnedQueued when rejected delivery restores an assignment to its admitted role immediately before that role retires. It delivers no input after Step::Stop, matching the interpreter lifecycle law.

Realization gate

Canonical construction, submission, management, outcomes, and worker completion syntax are owned by atomic-actor-devx.md. The exact production-source binding harness proves final-generation issuance, permanent exhaustion without wrap, complete rejected-key return, and preservation of an existing binding when rebinding cannot issue a generation. Real aggregate traces now cover shutdown from every reachable direct-worker and recovery phase, including activation-capacity and recovery-source waiters. A separate account-directory model now matches the production aggregate's automatic and explicit binding, capacity rejection and release, same-role preservation, cross-role generation, stale expectation, and unbind results without reading production state. The same independent customer-custody model now compares all 24 delivery-acceptance, completion, exact-exit, and shutdown orders against FIFO and KeyedPool. The keyed adapter also proves that every customer outcome retains the original binding generation and role. Recovery/shutdown parity is now closed by direct public traces: concurrent failures serialize the one recovery source in role order; every accepted, rejected, corrupt, or unattempted worker preparation and restart-schedule result returned after shutdown emits no new worker work; an accepted restart timer is cancelled; and accepted or rejected worker shutdown settlement reunites with the exact worker exit in either order. The separate workshop oracle checks the same ownership equations and explores 22,621 generated recovery/shutdown prefixes in debug and optimized builds. It uses no production state projection or second actor transition. Bombay's separately documented root transfer remains an upstream integration requirement.

No generic pool engine, optional key, selector mode, cloned key evidence, generation inference, permanent tombstone, stable proxy, structural completion route, helper alias, or compatibility spelling may enter the replacement. Repository-wide verification status and remaining gates are owned by atomic-actor-verification.md.

Normalized aggregate laws

These documents state the complete control states, retained data, transitions, outputs, rejections, and terminal paths for the five atomic actor aggregates. They are implementation-independent domain contracts. The adjacent catalogue documents map those laws onto Bombay's concrete typed behavior algebra.

Each law distinguishes actor-model requirements, derived library construction, and deliberate Bombay policy. Pseudocode identifiers describe semantic values; they are not additional exported Rust names.

Stable proxy falsification model

Status and authority

This document is the AA-01 independent semantic model for a stable worker proxy. It is a non-production falsification oracle. It does not define Rust types, a second behavior algebra, an interpreter contract, or evidence that a solution-matrix row is implemented. It is authoritative for the StableProxy behavior it covers. stable-proxy.md maps that behavior to the selected implementation, and atomic-runtime-settlement.md owns runtime interpretation and custody.

The actor-model law used here is fresh allocation: creating a replacement must establish a fresh actor rather than overwrite an existing address. Staged creator-local correlation, commit-before-dependent-effects ordering, exact installation, activation, owner-only control, and drain policy are Bombay derivations or policy choices. The stable public identity and replacement protocol are template laws.

Runtime route selection is owned normatively by docs/atomic-runtime-settlement.md. The proxy issues and stores only a CreationId; it never chooses or stores a runtime route before emitting CreateChild. Any older reservation label in the transition oracle denotes that creator-visible correlation before interpretation and routed evidence only inside the returned runtime settlement. It does not authorize a separate route request, waiting phase, public route, or combined value shared by proxy and Bombay.

Older shutdown labels that distinguish worker-return order describe semantic cases, not required Rust variants. Once the worker has stopped, the retained current product is the worker, exact stop, remaining initialization or activation value, and an optional exact shutdown receipt. Absence is lawful only when no shutdown request was emitted. H147 proves that separate AfterDeparture, AfterStop, and terminal *AfterStop Rust alternatives add arrival history without changing an accepted transition.

The model must falsify designs that make any of these claims false:

  1. One proxy owns at most one installed worker incarnation.
  2. A service command is sent only to the exact current incarnation in Ready.
  3. Installation is not readiness.
  4. Replacement drains the exact predecessor and creates a fresh successor.
  5. Every accepted transition produces one next state and one complete named action product; no effect is ambient.
  6. Shutdown closes admission and settles every definition, creation, initialization, activation, and incarnation the proxy still owns.
  7. Stale, duplicate, foreign, and contradictory facts cannot advance state.

“Atomic” below means one local Behavior fold commits a state and its complete Actions. It does not claim atomic delivery, creation, or cross-actor work.

Semantic values

The following names are model vocabulary, not proposed public Rust names.

BirthKind =
    Initial
  | Replacement { replaces: WorkerIncarnation }

BirthAttempt = the fresh, non-reused CreationId issued by the proxy
RoutedBirth = interpreter-private { attempt: BirthAttempt, route }
WorkerRecipient = proxy-private routable capability for one committed worker birth
WorkerIncarnationEvidence = opaque non-routable provenance for that birth
WorkerIncarnation = private { recipient: WorkerRecipient, evidence: WorkerIncarnationEvidence }
InitSettlement = complete initialization effects retained by the lifecycle host
InitAttempt = exact correlation for host-owned initialization work
ActivationPlan = the concrete work required before the worker may be ready
ActivationPermit = a one-shot capability issued only after successful initialization
ActivationAttempt = a fresh, non-reused correlation for one consumed permit and plan

ActivationPhase =
    AwaitingStartSettlement
  | InFlight

DrainCompletion =
    ReturnToEmpty
  | StopProxy

ActivationFailure =
    StartRejected { request, reason }
  | Rejected { rejection }

WorkerInitializationFailure = EffectsRejected | InterpreterCorrupt
InitFailure = { failure: WorkerInitializationFailure, activation }

ExitEvidence =
    FromInitialization {
        observation, stop
    }
  | FromObserver {
        observation, stop
    }

ExitSettlement =
    Observed { evidence: ExitEvidence }
  | Transferred {
        observation, worker: WorkerIncarnation, reason
    }

WorkerDrain =
    Exited { exit: ExitSettlement }
  | Transferred { residual }

PreReadyStop =
    DuringInit {
        activation,
        exit: ExitSettlement
    }
  | InitializedAfterExit {
        permit, activation,
        exit: ExitSettlement
    }
  | ReadyAfterExit {
        attempt, proof,
        exit: ExitSettlement
    }

BirthDrainResult =
    FoldRejected {
        creation, error, definition_and_plan
    }
  | HostRejected {
        creation, rejection, prepared_init, activation
    }
  | Contradiction { facts }

InitDrainWork =
    Initialized { permit, activation }
  | Rejected { rejection, activation }

InitDrainResult =
    WorkAndExit {
        work: InitDrainWork,
        exit: ExitSettlement
    }
  | FailureAndExit {
        failure: InitFailure,
        exit: ExitSettlement
    }
  | StoppedDuringInit {
        activation,
        exit: ExitSettlement
    }
  | Transferred {
        phase: InitDrainPhase,
        residual
    }

InitDrainPhase =
    AwaitingBoth { attempt: InitAttempt }
  | InitSettled {
        work: InitDrainWork
    }
  | ExitObserved {
        attempt: InitAttempt,
        exit: ExitSettlement
    }

ActivationDrainResult =
    StartRejected { request, reason }
  | ReadyAfterCancel { proof }
  | RejectedAfterCancel { rejection }

ActivationDrainPhase =
    AwaitingBoth { phase: ActivationPhase }
  | ActivationSettled { result: ActivationDrainResult }
  | ExitObserved {
        phase: ActivationPhase,
        exit: ExitSettlement
    }

An attempt is neither an address nor proof of freshness. A creation becomes an installed incarnation only when the interpreter commits fresh host ownership. All correlation values are exact and non-reused. Two proxies issuing their first worker attempt must still produce unequal evidence; a local ordinal is diagnostic data, not identity. Sequence arithmetic, address reuse, timing, or adjacency cannot manufacture provenance.

The proxy never publishes WorkerRecipient or the private WorkerIncarnation product. It alone routes service through worker.recipient. Parent outcomes project only WorkerIncarnationEvidence; the stable proxy remains the sole externally routable service capability.

Every payload in this model is complete and owned. Field names therefore use domain words such as worker, request, rejection, stop, and exit without repeating complete_ or structural implementation phrases.

Complete state sum

Each variant owns exactly the values listed. kind is the closed BirthKind sum, not an optional predecessor.

Dormant
    no installation has ever been attempted

Creating {
    kind, reservation: ChildReservation,
    stopped: Option<ExitSettlement>
}
    one complete worker definition and activation plan have moved into the
    staged creation action and its unresolved settlement; `stopped` is exactly
    absence or one authoritative pre-birth stop

Initializing {
    kind, worker: WorkerIncarnation, attempt: InitAttempt,
    stopped: Option<ExitSettlement>
}
    installation committed; the lifecycle host owns unresolved initialization
    settlement and the activation plan under this exact correlation; the proxy
    retains at most one already-arrived exact stop

Activating {
    kind, worker: WorkerIncarnation,
    attempt: ActivationAttempt, phase: ActivationPhase,
    stopped: Option<ExitSettlement>
}
    one exact permit and plan were consumed by one `BeginActivation` action;
    stop absence/presence remains current input to the readiness decision

Ready { worker: WorkerIncarnation }
    the one routable exact current worker

EmptyInitial
    the initial operation failed before installation committed

EmptyAfter { previous: WorkerIncarnation }
    a previously installed incarnation is terminally settled

StoppingForReplacement {
    current: WorkerIncarnation,
    next: ChildReservation,
    replacement
}
    the predecessor is being drained; the successor definition has not moved
    into creation yet

DrainingCreation { kind, reservation: ChildReservation }
    shutdown owns an unresolved creation settlement

DrainingCreationAfterExit {
    kind, reservation: ChildReservation,
    exit: ExitSettlement
}
    shutdown owns creation settlement and already has the pre-birth exit

DrainingInitFailure {
    kind, worker: WorkerIncarnation, failure: InitFailure,
    completion: DrainCompletion
}

DrainingInit {
    kind, worker: WorkerIncarnation, phase: InitDrainPhase
}

DrainingActivationFailure {
    kind, worker: WorkerIncarnation, attempt: ActivationAttempt,
    failure: ActivationFailure, completion: DrainCompletion
}

DrainingActivation {
    kind, worker: WorkerIncarnation, attempt: ActivationAttempt,
    phase: ActivationDrainPhase
}

DrainingWorker { worker: WorkerIncarnation }
    one shutdown/worker-exit observation remains unresolved

Stopped
    terminal; no mailbox event is admitted

EmptyInitial and EmptyAfter are distinct because only the latter has replacement provenance. The drain variants contain closed work/cause and join sums; they do not coordinate optional fields, cross-product flags, or already-settled live combinations.

At most one of Initializing, Activating, Ready, StoppingForReplacement, DrainingInit*, DrainingActivation*, or DrainingWorker can exist, proving the installed-incarnation bound structurally. Creating and DrainingCreation* own no installed capability.

The only empty-state projections are explicit:

PreBirthEmpty(Initial) = EmptyInitial
PreBirthEmpty(Replacement { replaces }) = EmptyAfter { previous: replaces }
PostBirthEmpty(worker) = EmptyAfter { previous: worker }

Therefore an initial attempt that committed an incarnation and then stopped or failed cannot return to EmptyInitial.

Complete input sum

There are three ingress lanes. They are distinct protocols, even where the table presents them together.

Public service input

Service { sender, command }

Private owner control input

InstallInitial { definition, activation }
Replace { definition, activation }
Shutdown

Only the established structural owner can construct the control capability. Clients can construct only the worker's concrete service protocol.

Lifecycle facts

BirthResult =
    FoldRejected { reservation, definition_and_plan, error }
  | HostRejected {
        reservation, behavior, init_actions, activation, reason
    }
  | Committed {
        reservation, worker: WorkerIncarnation, init: InitAttempt
    }

InitResult =
    Initialized {
        worker: WorkerIncarnation, init: InitAttempt,
        permit: ActivationPermit, activation: ActivationPlan
    }
  | EffectsRejected {
        worker: WorkerIncarnation, init: InitAttempt,
        failure: WorkerInitializationFailure, activation: ActivationPlan
    }
  | Stopped {
        worker: WorkerIncarnation, init: InitAttempt,
        activation: ActivationPlan,
        exit: ExitEvidence
    }

ActivationStartResult =
    Accepted { worker: WorkerIncarnation, attempt: ActivationAttempt }
  | Rejected {
        worker: WorkerIncarnation, attempt: ActivationAttempt,
        request, reason
    }

ActivationResult =
    Ready { worker: WorkerIncarnation, attempt: ActivationAttempt, proof }
  | Rejected { worker: WorkerIncarnation, attempt: ActivationAttempt, rejection }
  | ReadyAfterCancel { worker: WorkerIncarnation, attempt: ActivationAttempt, proof }
  | RejectedAfterCancel {
        worker: WorkerIncarnation, attempt: ActivationAttempt, rejection
    }

WorkerExit =
    BeforeBirth {
        reservation: ChildReservation,
        evidence: ExitEvidence
    }
  | AfterBirth {
        worker: WorkerIncarnation,
        evidence: ExitEvidence
    }

ProxyDiagnostic =
    UnexpectedWorkerReservation { phase, result: ReservationResult }
  | UnexpectedWorkerStart { phase, worker: WorkerStart }
  | UnexpectedWorkerStop { phase, stopped: WorkerStop }
  | UnexpectedWorkerInitialization { phase, initialization: WorkerInitialization }
  | UnexpectedWorkerActivation { phase, activation: WorkerActivation }
  | UnexpectedWorkerShutdown { phase, shutdown: WorkerShutdown }

Each alternative owns the complete unexpected input. phase is observable status data, not correlation authority. The exact expected reservation, worker, attempt, or shutdown token remains solely in the unchanged proxy state. Requiring the diagnostic to own that token as well would either duplicate an affine authority or make unchanged-state preservation impossible in safe Rust.

The split between activation start settlement and later activation result is intentional. A typed Ready value injected by a test is only model input. It is not implementation evidence.

Delivery rejection for service sends, parent reports, worker shutdowns, and logical cancellation remains lifecycle-host settlement rather than proxy mailbox input. Those settlements are still mandatory and must be witnessed in AA-06; excluding them from this input sum does not discard them or make the proxy their universal rejection owner.

The proxy's normal template report remains the solution's four-variant sum:

ParentReport =
    InitialInstallation { outcome: InstallationOutcome }
  | Replacement { outcome: ReplacementOutcome }
  | WorkerStopped { stop }
  | Unavailable { sender, phase, command }

InstallationOutcome =
    Rejected { definition_and_plan, phase, reason }
  | Resolved { result: WorkerStartResult }

ReplacementOutcome =
    Rejected { definition_and_plan, phase, reason }
  | CancelledBeforeBirth {
        replaces: WorkerIncarnationEvidence,
        replacement,
        reason: Shutdown
    }
  | Resolved {
        replaces: WorkerIncarnationEvidence, result: WorkerStartResult
    }

WorkerStartResult =
    CreationRejected {
        rejection: WorkerCreationRejection,
        activation,
        stopped: None | ExactWorkerStop
    }
  | Ready { attempt: WorkerAttempt, readiness }
  | Unavailable { attempt: WorkerAttempt, drain: WorkerDrain }

WorkerCreationRejection is the sole owner of the exact pre-commit cause and returned worker value. WorkerDrain is the sole owner of the exact committed worker failure cause and every proxy-held affine value. WorkerStartResult classifies only the three decisions its consumer makes; it does not repeat either nested cause as another outer alternative. stopped is present on a creation rejection only when the proxy had already accepted the exact stop.

Every attempt and replaces field in ParentReport is opaque evidence. A WorkerStopped report likewise contains terminal provenance and no WorkerRecipient. The owner can correlate lifecycle without acquiring a delivery route around the stable proxy.

Control rejection and contradiction are nested outcomes, not additional top-level parent-report variants. Shutdown completes through behavior termination and lifecycle-host settlement; it is not a fifth parent report. An owner never rebuilds one atomic outcome by joining several lower-level reports.

ProxyDiagnostic is deliberately not smuggled into that sum. It travels on the separate model-required diagnostics lane to the established owner. This is part of the recorded product disagreement and must be reconciled before production authority changes.

For non-shutdown operations, the atomic parent outcome carries every proxy-owned leftover. A creation rejection carries the complete creation rejection, activation plan, and any already accepted exact stop. An unavailable committed worker carries one WorkerDrain, whose exhaustive alternative owns the exact initialization, activation, early-stop, shutdown, and stop values. The lifecycle host separately retains the complete concrete action settlement in the worker environment. That settlement follows the one runtime retirement path; it is not a second Behavior outcome channel.

During shutdown there is deliberately no parent report. The lifecycle host receives BirthDrainResult for a pre-birth behavior/host rejection or contradiction. After commit it receives exactly one InitDrainResult: completed initialization work plus exact exit settlement, a stop produced by initialization with the unstarted plan, or a forced transfer containing the complete unresolved join and residual ownership. These are the only initialization-leftover alternatives; none may be dropped or reconstructed. This enriches the solution's abbreviated nested outcomes only inside the non-production oracle and remains an AA-06 runtime proof obligation.

Initialization and activation share only WorkerStopping, whose shutdown-result/stop law is identical. Their outer shutdown state is not one generic product: initialization has no pending domain value, whereas activation owns a real waiting-for-start or running value. A unit, marker, ignored field, or fabricated initialization token may not be introduced to make those shapes appear substitutable. Each concrete state must store only the exact work and worker-return values that remain current.

For initialization, the current work value is exactly Option<WorkerInitializationRetirement>: absence means the result has not returned; presence owns the complete result while worker departure remains unfinished. A second result cannot replace the first and is returned complete. No separate pending/returned initialization sum is lawful. Its stopped outcome owns Option<initialization stop> rather than an arrival-order alternative: presence retains the initializer's independently returned stop when the enclosing worker already owns the observed stop; absence means the initializer stop occupies that enclosing worker slot.

WorkerExit::BeforeBirth is admissible only in a state that owns the same ChildReservation. AfterBirth is admissible only in a state that owns its worker incarnation. The attempt and creator-local route are reserved, stored, emitted, compared, and retired as one private product. No field is inferred from the other; no optional field, address inference, or timing decides which provenance is present.

The lifecycle host, not Initializing, owns the linear InitSettlement and ActivationPlan while initialization work is unresolved. The proxy owns only InitAttempt. A matching InitResult transfers the exact permit/plan, failure-classification/plan, or stopped/plan product back once while the host retains the complete rejected or corrupt settlement for retirement. This is an intentional falsification-model clarification of the solution's shorthand Initializing { initialization_settlement, activation_plan }; AA-02 and AA-06 must prove a concrete locked-boundary realization before that shorthand can become Rust state.

Authorized readiness chain

Readiness is valid only if all of this chain is realized through the locked Behavior -> Actions boundary:

  1. Fresh creation commits one exact installed incarnation, closed to service.
  2. Initialization actions settle successfully for that incarnation.
  3. Settlement issues the one-shot ActivationPermit tied to that incarnation.
  4. The proxy reserves a fresh ActivationAttempt and, in the same fold, consumes the permit and concrete plan into an explicit BeginActivation action.
  5. The activation interpreter accepts or rejects that complete action. If accepted, it—not a test harness or arbitrary client—owns the in-flight work and the unique authority able to produce the result.
  6. Only Ready { worker, attempt, proof } from that accepted work can enter Ready.
  7. Rejection, stop, cancellation, a foreign incarnation, a wrong attempt, a duplicate, or a late result cannot publish readiness.

Who produces Ready: the concrete immediate or asynchronous activation interpreter designated by the consumed permit and plan. Who authorizes it: the exact one-shot permit obtained from successful initialization settlement. What starts asynchronous work: the real BeginActivation item in Actions. What correlates it: both exact incarnation and fresh activation attempt. Who owns it while in flight: the lifecycle host's exact activation settlement record, while the proxy owns the corresponding semantic waiting state.

The concrete capability representation and interpreter integration remain open for AA-03 and AA-06. If they cannot be expressed without changing locked foundations, that is a falsification result. This section must not be replaced by a helper that mints Ready directly.

Required falsification-model effect product

The governing solution currently names these six proxy lanes:

worker_deliveries
worker_creations
worker_creation_observations
worker_stop_observations
worker_shutdowns
parent_reports

That product is insufficient for this model because the proxy itself emits two activation operations and must continue after rejecting lifecycle facts. The minimum model product therefore adds three concrete typed send lanes:

activation_begin_requests: BeginActivation
activation_cancel_requests: CancelActivation
diagnostics: ProxyDiagnostic

The resulting nine-lane product is a non-production falsification requirement, not an amendment to design authority. It records a focused disagreement with the solution's six-lane product. AA-03 may not implement activation until the solution, matrix, retained-core decision, and research audit are reconciled or an existing named lane is proven to own the same exact operation without reinterpretation.

The fold returns the real Actions, including its next behavior or termination decision. That decision is not an extra effect lane. Initialization settlement remains an interpreter/lifecycle-host responsibility and is not an ambient behavior effect.

An emitted item transfers its complete value to action settlement. State retains only correlation and ownership that legitimately coexist with the emitted item. Creations still precede dependent observations and sends. The relative order of the independent named send lanes remains an interpreter obligation; AA-06 must prove the selected order rather than infer it from product position.

Creation must commit before same-action sends or observations that depend on the new child. Initialization settlement precedes BeginActivation. Replacement shutdown precedes successor creation because the successor definition remains in StoppingForReplacement until the predecessor's exact worker exit. No row emits both service delivery and unavailability.

Ownership table

ValueOwned before acceptanceOwned after action emissionOn rejection or final settlement
Initial/replacement definition and planincoming owner-control value, or StoppingForReplacement while predecessor drainscomplete staged creation item/settlementreturned complete by typed control or creation rejection; never reconstructed
Child reservationproxy state and matching birth/exit observation contractsthe attempt and creator-local route travel as one private productconsumed once by matching result; a mismatched attempt or route is rejected complete and neither is inferred
Worker incarnationinterpreter host after committed birth; proxy stores the worker capabilitydelivery/stop actions borrow no second ownership claim; host retains lifecycle ownershipmoves through a drain until exact exit settlement; never inferred from a nonce
Initialization actionscommitted initialization settlementconcrete worker environmentevery item is accepted, rejected, or not attempted; the exact settlement transfers through runtime retirement and never enters proxy state
Activation plan before initialization settlesstaged birth settlement, then lifecycle-host initialization workproxy stores only InitAttempt; the matching result returns the same plan with a permit, failure classification, or stophost rejection returns it with prepared initialization; effects rejection retains it through exit drain; it is never reconstructed or silently dropped
Activation permit and initialized planexact Initialized resultconsumed together by BeginActivation, or by a typed not-activated shutdown/early-stop settlementstart rejection returns the complete unaccepted request; accepted work remains host-owned
Activation attempt and result authorityreserved by proxy; authority minted only by accepted activation interpretationhost owns in-flight authority, proxy owns matching waiting correlationexact result consumes once; cancellation closes publication but does not fabricate physical cancellation
Service sender and commandincoming Service valueexact worker delivery only in Ready, otherwise complete Unavailable parent reportdelivery rejection belongs to the lifecycle host; proxy does not replay implicitly
Replacement definitionincoming Replace, then StoppingForReplacementmoves to creation only after exact predecessor stopoverlap returns it complete; shutdown settles it without creating a successor
Worker-exit observationlifecycle host under the child reservation or worker incarnationremains host-owned while the proxy stores correlation; one authoritative init stop or observed exit yields ExitSettlementsatisfied exactly once, or transferred to residual lifecycle ownership; a later result is diagnostic
Worker exitlifecycle host until delivered in WorkerExitconsumed into an early-stop join, drain, empty transition, or one parent reportduplicates, wrong-provenance, and foreign results move to diagnostics
Unexpected lifecycle inputincoming lifecycle resultcomplete input and current phase move once to diagnostics; proxy state is unchangeddiagnostic delivery rejection is settled by the lifecycle host without recursion
Parent reportproxy action item until interpretationparent-delivery settlement recordrejection never rewinds proxy state and is settled by the proxy host

Transition notation

The total matrix uses these cells:

  • I0: accept initial install; reserve one fresh attempt/route product, enter Creating(Initial), and emit one fresh creation plus its observation.
  • R0: accept replacement from Ready; reserve the complete successor attempt/route product before emitting one exact predecessor shutdown, then enter StoppingForReplacement retaining the complete successor.
  • R1: accept replacement from EmptyAfter; reserve the complete successor product and enter Creating(Replacement { replaces }) and emit creation.
  • C-: reject control with the complete submitted definition/plan and current phase. Repeated shutdown is handled by S= instead.
  • D+: deliver the untouched command once to the exact Ready incarnation.
  • U: emit one Unavailable report with untouched sender, command, and phase.
  • S0: close immediately, settle any control outcome, and enter Stopped.
  • S1: close admission and enter the corresponding drain variant without duplicating an already-emitted action.
  • S=: shutdown is already in progress; remain in the same drain state and emit no duplicate child shutdown or cancellation.
  • BR, IR, AS, AR, WE: apply the matching-result rules below.
  • F-: keep the same semantic state and emit exactly one ProxyDiagnostic on diagnostics; every other action lane is empty and the next decision is Continue.
  • NA: the event is not admitted because Stopped is terminal. Late settlements are owned by the lifecycle host, not a stopped mailbox.

All BR, IR, AS, AR, and WE cells mean “matching exact correlation only”; every mismatch is F-.

F- is a continuing diagnostic law, not Behavior::Error. The concrete diagnostic alternative names the unexpected input kind, retains the complete original input, and carries the current observable proxy phase. It does not copy the proxy's expected correlation authority out of unchanged state. Creating and initializing each have one public phase; their privately retained optional stop is ownership needed by the later result, not another public work phase. If diagnostic delivery is rejected, the lifecycle host settles that complete action directly and does not recursively send another diagnostic.

Reservation of both attempt and route is a pure, fallible precondition of I0, R0, and R1. A collision or exhaustion of either component returns the complete input through the appropriate nested InstallationOutcome::Rejected or ReplacementOutcome::Rejected and leaves the state unchanged. It never emits creation and never replaces an existing binding.

Total state/event matrix

StateInstallReplaceServiceShutdownBirth resultInit resultActivation startActivation resultWorker exit
DormantI0C-US0F-F-F-F-F-
CreatingC-C-US1BRF-F-F-WE
InitializingC-C-US1F-IRF-F-WE
ActivatingC-C-US1F-F-ASARWE
ReadyC-R0D+S1F-F-F-F-WE
EmptyInitialC-C-US0F-F-F-F-F-
EmptyAfterC-R1US0F-F-F-F-F-
StoppingForReplacementC-C-US1F-F-F-F-WE
DrainingCreationC-C-US=BRF-F-F-WE
DrainingCreationAfterExitC-C-US=BRF-F-F-F-
DrainingInitFailureC-C-US1/S=F-F-F-F-WE
DrainingInitC-C-US=F-IRF-F-WE
DrainingActivationFailureC-C-US1/S=F-F-F-F-WE
DrainingActivationC-C-US=F-F-ASARWE
DrainingWorkerC-C-US=F-F-F-F-WE
StoppedNANANANANANANANANA

The matrix is exhaustive over the complete input categories. Nested outcome rules below make each matching cell exhaustive over its result sum.

Shutdown expansion (S0, S1, and S=)

  • Dormant, EmptyInitial, and EmptyAfter own no unresolved child work; they return the terminal behavior decision and transfer shutdown settlement to the lifecycle host (S0); no parent report is fabricated.
  • Creating with no stop becomes DrainingCreation; with a stop it becomes DrainingCreationAfterExit. The already-transferred creation is not reconstructed or physically cancelled.
  • Initializing with no stop becomes DrainingInit(AwaitingBoth) and initiates exact worker drain. With a stop it uses ExitObserved and emits no duplicate worker shutdown.
  • Activating becomes DrainingActivation, preserving its ActivationPhase in AwaitingBoth when no stop is present, logically closes readiness publication, and emits the exact cancellation/drain actions. With a stop it preserves the exit in ExitObserved and emits no duplicate worker shutdown.
  • Ready becomes DrainingWorker and emits one exact worker shutdown plus its worker-exit observation.
  • StoppingForReplacement settles the still-local replacement definition as a nested ReplacementOutcome::CancelledBeforeBirth, becomes DrainingWorker for the predecessor, and does not create the successor.
  • Shutdown in DrainingInitFailure or DrainingActivationFailure changes DrainCompletion from ReturnToEmpty to StopProxy. It does not lose the complete failure and emits no duplicate child drain (S1). If the completion is already StopProxy, shutdown is S=.
  • All shutdown-owned drain states use S=. They retain their exact state and emit no duplicate cancellation, shutdown, or observation.

Matching-result rules

Birth result (BR)

  • In Creating without a stop, FoldRejected or HostRejected emits the corresponding complete initial/replacement outcome and enters EmptyInitial for Initial or EmptyAfter { previous: replaces } for Replacement. Committed enters Initializing with the exact initialization correlation while the lifecycle host retains the linear settlement and plan.
  • In Creating with a stop, rejection produces one Contradiction containing both complete authoritative inputs, then enters the pre-commit empty state. Commit enters Initializing carrying that stop; it cannot publish readiness.
  • In DrainingCreation, rejection settles shutdown and enters Stopped. FoldRejected and HostRejected transfer their complete values through the corresponding BirthDrainResult variant. Commit enters DrainingInit(AwaitingBoth); exact initialization and terminal ownership must both settle.
  • In DrainingCreationAfterExit, rejection produces the complete contradiction, transfers it as BirthDrainResult::Contradiction, and enters Stopped. Commit enters DrainingInit with the retained exit in ExitObserved.

No creation rejection can coexist with a successful birth report. A committed creation is never reclassified as rejected because later initialization fails.

Init result (IR)

  • In Initializing without a stop, only a result matching both worker and InitAttempt is admissible. Initialized reserves a fresh activation attempt and, in the same fold, emits the exact BeginActivation action and enters Activating with AwaitingStartSettlement. EffectsRejected enters DrainingInitFailure with both proxy-owned values returned by the result—the closed failure classification and still-unstarted activation plan—then initiates exact drain. Stopped settles its returned plan as never activated and satisfies the outstanding stop observation with that same authoritative result. Its exit field must be ExitEvidence::FromInitialization. It emits StoppedBeforeReady carrying PreReadyStop::DuringInit plus the corresponding ExitSettlement::Observed, then enters EmptyAfter { previous: worker }.
  • In Initializing with a stop, every outcome settles initialization without beginning activation. Only the exact initialization attempt is admissible. Initialized emits PreReadyStop::InitializedAfterExit carrying its returned permit/plan and the already-satisfied worker-exit observation. Stopped reconciles its exact stop with the stored exit and requires exit = ExitEvidence::FromObserver, then emits DuringInit with the corresponding Observed settlement; it does not settle the observation twice. EffectsRejected combines its failure classification and returned plan with the same exit settlement. The lifecycle host retains the complete action settlement. None can emit Ready; all enter EmptyAfter { previous: worker }.
  • DrainingInitFailure already owns a settled rejection. It waits only for the exact worker exit. With ReturnToEmpty, it emits one InitEffectsRejected parent outcome carrying the failure classification, unstarted plan, and exit settlement. With StopProxy, it transfers exactly InitDrainResult::FailureAndExit instead. Shutdown changes only that completion and never discards either value.
  • In DrainingInit, an exact init result changes AwaitingBoth to InitSettled and stores one exhaustive InitDrainWork, including the permit/plan or failure-classification/plan pair. From ExitObserved, the same result closes the join by transferring WorkAndExit to the lifecycle host and enters Stopped. InitResult::Stopped closes directly as StoppedDuringInit: from AwaitingBoth it satisfies and retires the exact outstanding observation with the same authoritative stop; from ExitObserved it reconciles the already-satisfied observation and does not settle it twice. A separate worker exit changes AwaitingBoth to ExitObserved, or closes InitSettled as WorkAndExit. A foreign correlation emits ProxyDiagnostic; two authoritative inputs with the same correlation but conflicting stop data emit the atomic Contradiction retaining both. No live state represents both obligations settled.

The exact host ordering used to interpret and settle initialization actions is an open foundational realization. These rules state the ownership constraint; they do not claim that AA-01 implements it.

Activation start (AS) and result (AR)

  • In Activating(AwaitingStartSettlement) without a stop, exact start acceptance changes only phase to InFlight; the host then owns work and result authority. Exact start rejection enters DrainingActivationFailure with the complete unaccepted request and initiates exact drain.
  • An activation result is authorized only in Activating(InFlight). Exact Ready enters Ready and emits the initial/replacement readiness outcome. Exact rejection enters DrainingActivationFailure, retains the complete rejection, and initiates exact drain. A result received before start acceptance is F-; the activation interpreter must causally publish acceptance before releasing its result authority. Cancellation-qualified results in a non-cancelling state are F- and cannot be reinterpreted.
  • In Activating with a stop, exact start acceptance changes phase to InFlight; exact start rejection emits its complete atomic outcome with the retained stop. An authorized exact result in InFlight emits PreReadyStop::ReadyAfterExit for Ready, carrying the attempt, authority proof, and worker-exit settlement. A rejection emits the complete activation-rejection outcome with the same exit settlement. Every case enters EmptyAfter { previous: worker }; none publishes readiness.
  • DrainingActivationFailure already owns a settled activation failure. It waits only for the exact worker exit, then emits the complete failure outcome. Shutdown changes its drain completion to Stopped without discarding failure provenance.
  • In DrainingActivation, matching start acceptance changes the activation phase inside AwaitingBoth or ExitObserved from AwaitingStartSettlement to InFlight. Matching start rejection changes AwaitingBoth to ActivationSettled, or closes ExitObserved and stops. An exact late result from InFlight follows the same two transitions. Neither ordinary Ready racing with cancellation nor ReadyAfterCancel is published. A result before start acceptance is F- under the causal interpreter policy; a result after ActivationSettled is a duplicate. Ordinary Ready/Rejected racing the logical close are normalized into the corresponding after-cancel settlement without publishing availability. An exact stop changes AwaitingBoth to ExitObserved, or closes ActivationSettled and stops. No live state represents both obligations settled.

The causal acceptance-before-result rule is an explicit Bombay interpreter policy and an AA-06 proof obligation, not a general actor-model guarantee. If the real boundary cannot enforce it, AA-03 must replace ActivationPhase with a truthful closed out-of-order join before production code exists.

Worker exit (WE)

  • Creating with no stop accepts only BeforeBirth with its child reservation, stores that exact stop, and still waits for the creation result to decide whether a birth committed. DrainingCreation similarly becomes DrainingCreationAfterExit.
  • Every WorkerExit must carry ExitEvidence::FromObserver; initialization exit evidence provenance on this ingress is wrong-kind and follows F-. An accepted exit is stored or emitted only after wrapping that delivered value in ExitSettlement::Observed.
  • Initializing and Activating with no stop accept only AfterBirth with their worker incarnation and store that exact stop. A second stop is F-.
  • Ready emits one complete WorkerStopped report and enters EmptyAfter { previous: worker }.
  • StoppingForReplacement emits the predecessor stop report and, in the same fold, transfers the retained successor through the already-reserved complete attempt/route product into the fresh creation action, entering Creating(Replacement { replaces }) with that same reservation.
  • In any DrainingInit*, DrainingActivation*, or DrainingWorker state, only AfterBirth with the owned worker incarnation can advance. It either completes the failure drain, records ExitObserved, or closes a shutdown join whose work is already settled. A second stop is F-. Final outcome waits for any still-owned settlement.
  • DrainingWorker consumes the exact stop, returns the behavior's terminal decision, and transfers final shutdown settlement to the lifecycle host. It emits no invented parent-report variant.

Overlap, stale input, and outcome laws

  • A second install or an install after Dormant is a typed rejection that returns its complete definition and plan.
  • A replacement is accepted only in Ready or EmptyAfter. Every overlap returns the complete submitted successor.
  • Every non-ready service command produces exactly one complete Unavailable report. No retry or implicit replay is promised.
  • A lifecycle fact can advance only the state owning its exact worker and attempt and expecting that fact kind. Wrong-kind facts are not reinterpreted.
  • Duplicate stop, creation, initialization, activation-start, activation result, and readiness inputs preserve proxy state and emit exactly one closed ProxyDiagnostic retaining the complete input.
  • Parent-report delivery rejection never rewinds the transition. The lifecycle host settles the complete rejected report.
  • A pre-readiness failure after committed installation is not reported as final until the exact incarnation and all transferred initialization or activation work are settled or transferred to terminal residual ownership.

First-slice non-features and proof obligations

AA-01 intentionally does not provide:

  • Rust proxy types, a fold, an executable local algebra, or test helpers;
  • the real initialization fold/settlement implementation and its exact host ordering;
  • a selected Rust representation for ActivationPermit, result authority, out-of-order activation joins, or asynchronous work;
  • accepted and rejected interpreter traces;
  • delivery settlement/rejection realization for service or parent reports;
  • deadline expiry, forced retirement, root residual settlement, or leak-free late-work ownership;
  • wrapper composition or initialization-order proof;
  • catalogue parity, builder syntax, compiler/DevX acceptance, or migration;
  • edits to the locked kernel, legacy actors, macros, testkit, or interpreters.

Consequently this document is ready only to guide AA-02’s focused failing regressions and to be compared against production authority. It is not implementation evidence. “Ready for comparison and policy enrichment” later requires real Behavior/Actions integration, accepted and rejected interpreter traces, applicable catalogue parity, wrapper-composition proof, complete shutdown/residual ownership, and compiler and DevX acceptance.

If AA-02 through AA-06 cannot realize any table cell through the locked boundary, the experiment records that focused counterexample. It must not invent a parallel actor contract or silently weaken the table.

Fixed-supervisor falsification model

Status and authority

This document is the AA-10 independent semantic model for one fixed supervisor. It is a non-production falsification oracle. It does not select Rust types, define another behavior algebra, implement a supervisor, or mark a row in docs/engineering/atomic-actor-solution.md implemented. That document remains the production design authority.

AA-10 is blocked, not complete. The state and transition oracle requires typed child terminal/drain settlement to return an emitted install or replacement when the proxy terminates without its normal outcome, but the locked boundary has no implementation witness for that transfer yet.

Fresh allocation is the actor-model law used here: every stable proxy and every worker incarnation behind it is freshly established rather than written over an existing address. Creator-local child reservations, commit before dependent effects, exact installed capabilities, action settlement, activation authorization, and actor-graph drain are Bombay derivations or policy choices. Ordered semantic roles, stable proxies, recovery policy, and fixed-topology failure reaction are template laws.

Runtime route selection is owned normatively by docs/atomic-runtime-settlement.md. The supervisor issues and stores only a CreationId for each proxy creation; it never chooses or stores a runtime route before emitting CreateChild. Any older reservation label below denotes that creator-visible correlation before interpretation and routed evidence only in the returned runtime settlement. It does not authorize a separate route request, waiting state, or public route.

The model must falsify designs that make any of these claims false:

  1. The roster is non-empty, ordered, and contains each semantic role once.
  2. Each live role owns at most one exact stable proxy.
  3. The supervisor consumes one atomic proxy outcome; it never reconstructs worker creation, initialization, activation, or readiness.
  4. A role is advertised ready only after its exact proxy reports a successful initial or replacement outcome.
  5. The configured positive activation bound limits unresolved proxy install/replace operations across the complete supervisor.
  6. A recovery admission is selected from one immutable roster snapshot. The membership partition, prepared replacements, fallible correlations, and budget charge commit in one fold; failure before that fold changes none of them. Later cross-actor realization resolves each admitted participant independently.
  7. Recovery timing, readiness, and activation authorization are independent prerequisites joined without flags.
  8. Stale, duplicate, foreign, wrong-kind, and contradictory facts cannot advance a member or charge recovery twice.
  9. Query is a total projection and cannot mutate topology, budget, recovery, authorization, or lifecycle ownership.
  10. Shutdown closes recovery and drains every owned or still-creating proxy exactly once while leaving unrelated application children untouched.
  11. Every accepted input produces one next state and one complete named action product. No effect is ambient.

“Atomic” means one local Behavior fold commits one supervisor state and its complete Actions. It does not claim atomic delivery, creation, or work across actors.

Model vocabulary

The following names describe the oracle. They are not proposed public Rust names.

Role = one semantic member label, unique inside this supervisor
RoleOrder = the declaration order retained for the supervisor lifetime

ProxyBirthAttempt = fresh non-reused CreationId issued by the supervisor
RoutedProxyBirth = interpreter-private { attempt: ProxyBirthAttempt, route }
ExactProxy = externally routable exact capability for one committed stable proxy
WorkerAttempt = opaque non-routable evidence for one started worker

OperationKind =
    Initial
  | Replacement { recovery: RecoveryTicket, replaces: WorkerAttempt }

OperationTicket = one affine ID paired with one private supervisor witness

ProxyControl =
    Start { definition, activation }
  | Replace { definition, activation }

OperationInput = {
    ticket: OperationTicket,
    kind: OperationKind,
    control: ProxyControl,
}

RecoveryTicket = fresh non-reused correlation for one complete recovery decision
RecoveryOrdinal = checked one-based lifetime recovery count of the triggering role
TimerCorrelation = { timer, generation }

RecoveryParticipant =
    Stopped {
        previous: WorkerAttempt,
        stop,
    }
  | Online { current: WorkerAttempt }
  | AwaitingInitial { phase: InitialPhase }

FailureReaction = RetireMember | StopSupervisor

ActorDrainPolicy =
    WaitForActorGraph
  | RetireActorGraphAfter { deadline }

DiagnosticDisposition =
    DeliverTo { route }
  | Terminate

LifecyclePublication =
    NotPublished
  | Published { route }

An attempt, ticket, timer generation, role, or child route is correlation, not actor identity or evidence of fresh allocation. Only committed creation yields an exact installed proxy. Sequence arithmetic, address reuse, timing, or adjacency cannot manufacture provenance.

Every payload named below is complete and owned. A state may retain an exact correlation after its value has moved into an action, but it cannot retain a second ownership claim on the moved value.

WorkerIncarnationEvidence is correlation and lifecycle provenance, not a recipient or transferable delivery capability. The proxy alone retains the routable worker capability. The only service capability the supervisor may publish or return is ProxyIncarnation, preserving the stable proxy as the one public communication path for the role.

OperationKind is supervisor settlement metadata. Only the matching concrete ProxyControl value is delivered to AA-01's private control protocol; the fixed supervisor does not widen the proxy message with its recovery ticket. The action settlement owns the metadata and control as one staged source-side product so rejection can return both without asking the proxy to echo either.

Construction domain

Worker-preparation correction

The original draft stored one callable factory and instructed the recovery transition to invoke it. That representation is rejected: application execution is not part of a pure Behavior transition. A callable used to prepare the initial roster is consumed before the supervisor exists and is not stored in the successful behavior.

Automatic recovery instead emits one typed batch worker-preparation action. Its accepted start settlement proves only that source work began. Its later typed result must return the complete worker-source authority, the ordered selected immutable role names, every WorkerSubmission, any exact rejection, and every untouched role name. Bombay interprets the statically selected capability; FixedSupervisor owns selection and the later state change. No callback, registry, erased response, or runtime lookup exists in Behavior.

H38 selects the typed batch action rather than a mandatory factory actor. The actor alternative adds a delivery settlement and later reply join; delivery acceptance cannot mean workers were prepared. The action uses H35 source settlement directly. Bombay will implement its exact static interpreter and retirement transfer through the required generic runtime contract. The atomic implementation targets that contract and does not wait for the present Bombay API shape. The old callable instruction below is not an alternate accepted path.

The source contract is a method-free static declaration over the concrete role, worker, and activation-plan types. One non-empty action owns the complete selected immutable-name batch; it never owns the unique member-role authorities, which remain in the pending recovery. Bombay observes each name only as &Role. Its late result is exactly a complete prepared group, the prepared prefix plus a worker rejection and untouched suffix, or a source rejection before the first submission. Corruption and no-attempt remain generic start settlement alternatives; FixedSupervisor must not repeat them in another sum.

One complete definition contains:

FixedDefinition = {
    initial_factory: ConstructionOnly,
    roles: OrderedNonEmptyUnique<Role>,
    activation,
    activation_limit: PositiveMaximum,
    recovery: {
        eligibility,
        worker_source: OnlyWhenAutomatic,
        strategy,
        budget,
        timing,
    },
    failure_reaction: FailureReaction,
    actor_drain: ActorDrainPolicy,
    diagnostics: DiagnosticDisposition,
    lifecycle: LifecyclePublication,
}

Duplicate roles, an empty roster, invalid timing, a non-positive activation limit, and a rejected initial factory call are construction failures. The initial factory prepares every initial definition before the supervisor exists or any initialization action is emitted. A failure returns all still-owned inputs and identifies the exact role; it cannot leave a partially constructed behavior. Success drops the callable before producing the behavior.

Replacement definitions arrive only through the typed batch action above. A closed heterogeneous worker sum is valid only when every variant exposes one common concrete public protocol. Different public protocols are different supervisors, not one erased envelope.

The canonical recovery value is constructed as Recovery::permanent(source, strategy, limit, release), Recovery::transient(source, strategy, limit, release), or Recovery::temporary(). The first two variants own the concrete source that crosses the worker-preparation action. The temporary alternative has no source, strategy, limit, or release field and requires no placeholder or annotation.

Lifecycle publication is genuinely optional. NotPublished constructs no event and requires no dummy route. Diagnostics remain mandatory through the independent DeliverTo | Terminate choice.

Every selected route retains its concrete logical, established, or mixed capability form and its corresponding static hosting obligations. The model does not normalize those routes into one runtime-selected envelope.

AA-10 deliberately selects no builder, typestate marker, callback, trait, or finished behavior spelling.

Normalized supervisor state

SupervisorState =
    Operating {
        definition,
        fleet: FixedFleet,
        budget: BudgetState,
    }
  | Draining {
        definition,
        fleet: DrainingFleet,
        budget: BudgetState,
        deadline: DeadlinePhase,
    }
  | Stopped

FixedFleet is one order-preserving partition of the declared roles. Each role has exactly one topology authority, held either by an independent Member or by one participant in exactly one RecoveryBatch. The immutable role value is allocated once. Lifecycle events, diagnostics, and an emitted worker-preparation action may retain read-only role names, but those names cannot select, move, recover, or retire a member. The application-facing values expose &Role, not the private shared representation. RecoveryBatch and its participants are one dependent semantic value: there is no separately mutable member map plus batch map whose flags may disagree. A later Rust experiment must find a concrete representation that preserves this equation.

The configured activation maximum is immutable. Occupancy is not a second counter: every occupied slot is owned by exactly one initial operation or one replacement whose input or proxy outcome is still pending. An exact proxy outcome releases the slot even when the predecessor stop is still outstanding. Capacity is the count of those exact unresolved operations. Waiting roles are discovered from RoleOrder, so a separate queue cannot disagree with member state.

The budget stores only committed evidence inside its active inclusive window. It is bounded by the configured maximum; a maximum of zero stores no admitted charge and denies every otherwise eligible decision.

Complete independent-member sum

Member =
    CreatingProxy {
        role,
        reservation: ProxyReservation,
        initial: OperationInput,
    }

  | CreatingProxyAfterExit {
        role,
        reservation: ProxyReservation,
        initial: OperationInput,
        exit,
    }

  | Starting {
        role,
        proxy: ProxyIncarnation,
        phase: InitialPhase,
    }

  | Online {
        role,
        proxy: ProxyIncarnation,
        worker: WorkerIncarnationEvidence,
    }

  | Empty {
        role,
        proxy: ProxyIncarnation,
        previous: WorkerIncarnationEvidence,
        cause,
    }

  | Stopping {
        role,
        proxy: ProxyIncarnation,
        cause,
        phase: ProxyStopPhase,
    }

  | Retired {
        role,
        cause,
    }
InitialPhase =
    WaitingForAuthorization { input: OperationInput }
  | Dispatched {
        ticket: OperationTicket,
        settlement: InputSettlementCorrelation,
    }
  | AwaitingOutcome { ticket: OperationTicket }

ProxyStopPhase =
    ShutdownDispatched { settlement: ShutdownSettlementCorrelation }
  | AwaitingExit
  | Rejected { rejection }

Starting owns no worker incarnation. Its unresolved operation kind is always Initial. Empty is possible only after one installed worker has stopped or a replacement attempt against such a predecessor has failed. Failure before any worker installation is irrecoverable for the current proxy contract and therefore enters Stopping or whole-supervisor drain; it cannot manufacture an Empty predecessor.

Stopping preserves a rejected shutdown reason while still waiting for exact proxy exit. Rejection is not reclassified as a successful stop. Under RetireActorGraphAfter, the deadline may transfer the remaining ownership to the lifecycle host; under WaitForActorGraph, the member can wait forever.

The accepted-stop carrier owns the unchanged other members and one complete stopped member. Recovery eligibility borrows the stopped member's terminal outcome when choosing policy; it does not store a second normal/abnormal label beside the outcome that already determines it.

Recovery partition

An admitted recovery batch owns all selected member-role authorities as one value. Its preparation action may temporarily own read-only names for those same roles, never another topology authority:

RecoveryBatch = {
    ticket: RecoveryTicket,
    trigger: RosterPosition,
    release: RestartReleaseState,
    members: Vec<RecoveryMember>,
}

RestartReleaseState =
    Ready
  | Scheduling { correlation: TimerCorrelation, request_settlement }
  | Waiting { correlation: TimerCorrelation }

RecoveryMember =
    Waiting { participant, prepared_replacement }
  | Replacing { participant_identity, replacement: WorkerReplacement }

WorkerReplacement = {
    previous_worker,
    readiness,
    stopped: None | Some { complete_stop },
    response: ReplacementResponse,
}

ReplacementResponse =
    InputPending { witness }
  | OutcomePending { operation }
  | OutcomeReturned { complete_outcome }
  | InputRejected { complete_settlement }

RosterPosition is assigned once at roster construction and moves with the unique member authority. Admission proves that members is non-empty, contains each selected position once, and contains trigger. OneForOne selects one position, OneForAll selects every eligible position, and RestForOne selects the trigger position and its eligible suffix. Physical collection placement is not declaration order.

The trigger position remains after that participant returns independently. A return removes exactly one position from members and restores one independent roster owner; the recovery retires only when members becomes empty. This is the same one-collection ownership equation as H32/H32r. It needs neither a parallel recovery table nor a split recovery when a middle participant returns.

Every participant owns exactly one prepared replacement until it is emitted. After emission, WorkerReplacement stores two independent current values: the optional complete predecessor stop and the proxy operation's current response. An online participant has no stop; an already-stopped participant has one. The response changes from input pending to outcome pending only after the exact receipt, then to the complete returned outcome. Exact input rejection instead stores the complete settlement without erasing an already-owned stop. Operating recovery consumes a completed or rejected product immediately; shutdown may retain the same product while proxy retirement remains independent.

An AwaitingInitial subject owns the complete InitialPhase; the enclosing Waiting phase separately owns exactly one prepared replacement. It cannot issue replacement until the initial operation atomically reports a ready worker, providing the exact predecessor. Initial failure removes that participant through the configured topology-failure reaction; it never treats an initial-empty proxy as replaceable.

The stopped trigger begins with Some(complete_stop) and input pending; an online coordinated peer begins with no stop and input pending. A matching peer stop fills only the optional stop and cannot open another recovery decision. If the replacement outcome arrives first, OutcomeReturned retains it until the exact stop report or its typed delivery settlement closes the reunion. Thus stop and replacement outcome are order-independent and each is accepted once.

StableProxy and FixedSupervisor own different work here. StableProxy owns the worker shutdown-resolution and successor-start sequence and emits the exact predecessor WorkerStopped report before its later replacement outcome. FixedSupervisor owns admission of those two owner reports, lifecycle publication, recovery capacity, and the rule that replacement readiness is not published until both reports have been admitted. The supervisor never repeats StableProxy's worker-control sequence.

The triggering worker's stop classification is consumed when recovery disposition is chosen; its immutable roster position remains as the recovery's trigger identity. RecoveryOrdinal is consumed when the release is calculated. The committed budget charge remains solely in BudgetState, where the next admission needs it. None is copied into RecoveryBatch. Immediate release and an accepted exact timer both produce RestartReleaseState::Ready; their arrival history cannot change a later decision. Schedule rejection transfers the exact rejected request directly into the configured failure reaction and therefore is not a stored release phase.

Readiness is derived from the participant's current worker ownership, timing from the batch's current RestartReleaseState, and authorization from current activation occupancy. There is no stored cross-product of these prerequisites. The transition that sees all three immediately emits the replacement input and stores one WorkerReplacement with exact stop absence or presence and InputPending; a ready-to-issue phase is never committed between turns.

Recovery batches may overlap in time only when their selected role sets are disjoint. Exact recovery tickets distinguish them. A role already in any batch, stopping, retired, or awaiting an admitted replacement is not selectable by another batch.

Complete input sum

Inputs arrive through distinct concrete protocol lanes.

Management input

Management =
    QueryStatus { reply_to }
  | QueryCapability { role, reply_to }
  | Shutdown

Query routes are temporary reply capabilities. They never become durable lifecycle or diagnostic owners.

Stable-proxy lifecycle input

ProxyBirthResult =
    FoldRejected { reservation, proxy_definition, error }
  | HostRejected { reservation, proxy, init_actions, reason }
  | Committed { reservation, proxy: ProxyIncarnation }

ProxyInputResult = ActionItemResult<
    ProxyOperation,
    ProxyInputReceipt { proxy: ProxyIncarnation, ticket: OperationTicket },
    ProxyInputRejection,
    Never,
>

ProxyReport =
    InitialInstallation { outcome }
  | Replacement { outcome }
  | WorkerStopped { stop, observed_at }
  | Unavailable { sender, phase, command }

ProxyExit =
    BeforeBirth { reservation: ProxyReservation, exit }
  | AfterBirth { proxy: ProxyIncarnation, exit }

ProxyShutdownSettlement =
    Accepted { proxy: ProxyIncarnation, correlation }
  | Rejected { proxy: ProxyIncarnation, correlation, request, reason }

The generic result owns whether interpretation was attempted. Acceptance owns only the receipt promised by the request. Rejection and corruption return the complete ProxyOperation; an unattempted result retains it unchanged. There is no supervisor-specific result sum or conversion seam.

ProxyReport is always accompanied by its exact child-source capability. The source capability, expected pending operation kind, and the replacement outcome's nested exact replaces: WorkerIncarnationEvidence together provide report correlation. That evidence must equal the participant's retained prior evidence. An initial operation occurs at most once for one exact proxy, and each later replacement names a fresh predecessor, so a delayed earlier report cannot satisfy a later pending operation. The supervisor does not add its operation or recovery ticket to AA-01's flat four-variant proxy report. Install/replace settlement is discharged before a later report from that input, so Dispatched -> AwaitingOutcome -> report is a causal Bombay interpreter policy, not an inference from arrival timing.

Recovery and drain input

RestartScheduleSettlement =
    Accepted { recovery: RecoveryTicket, timer: TimerCorrelation }
  | Rejected {
        recovery: RecoveryTicket,
        timer: TimerCorrelation,
        request,
        reason,
    }

RestartElapsed = { recovery: RecoveryTicket, timer: TimerCorrelation, observed_at }

DrainDeadlineSettlement =
    Accepted { timer: TimerCorrelation }
  | Rejected { timer: TimerCorrelation, request, reason }

DrainDeadline = { timer: TimerCorrelation, observed_at }

ActionSettlement = one closed lane-specific accepted, rejected, or
not-attempted settlement from the current action product

Workers and callers cannot author observed_at. The interpreter's monotonic clock supplies it with the authoritative stop or timer fact. A regressing clock fact is a typed rejection and cannot prune future evidence.

Unexpected input

UnexpectedInput = { input: FixedSupervisorEvent }

A mismatched input moves complete into one diagnostic outcome. The exact expected route, proxy, operation, recovery, or timer authority remains solely in current supervisor state. Copying it into the diagnostic would duplicate admission authority; moving it would contradict unchanged-state preservation. The unexpected input is not dropped, reinterpreted, or converted into Behavior::Error merely because it was unexpected.

Public projections

Status is a total read-only projection in declaration order:

MemberStatus =
    CreatingProxy
  | WaitingForActivationAuthorization
  | AwaitingProxyOutcome
  | Ready { proxy: ProxyIncarnation }
  | Empty
  | Recovering
  | Stopping
  | Retired

CapabilityResult =
    Ready { role, proxy: ProxyIncarnation }
  | Unavailable { role, phase }
  | UnknownRole { submitted_role }

The projections are exact:

Owned stateStatusCapability
CreatingProxy*CreatingProxyUnavailable
Starting(WaitingForAuthorization)WaitingForActivationAuthorizationUnavailable
Starting(Dispatched | AwaitingOutcome)AwaitingProxyOutcomeUnavailable
OnlineReady { proxy }Ready { proxy }
EmptyEmptyUnavailable
any RecoveryMemberRecoveringUnavailable
Stopping or any drain memberStoppingUnavailable
Retired or drained memberRetiredUnavailable

The supervisor never reports proxy-private worker-creation, initialization, or activation phases. Query emits one management reply and leaves the complete state byte-for-byte semantically unchanged. Reply rejection belongs to action settlement and cannot mutate the snapshot that was already produced.

Production witness H121 realizes this table directly from the current roster owners. It sorts status by immutable roster position and scans capability by borrowed role equality. Logical and exact reply routes select two named lanes in the ordinary action product; no copied roster, lookup table, query actor, or template-specific interpreter exists.

Production witness H123 realizes the exact initial-failure StopSupervisor row through the ordinary FixedShutdown transition. It emits one failure diagnostic, stops only committed proxies, retains pending proxy creations, and makes repeated shutdown idempotent. It adds no alternate drain state or response product.

Lifecycle and diagnostic values

LifecycleEvent =
    Started { role, proxy: ProxyIncarnation }
  | Restarted {
        role,
        proxy: ProxyIncarnation,
        recovery: RecoveryTicket,
    }
  | WorkerStopped { role, stop, disposition }
  | Unavailable { role, sender, phase, command }
  | MemberRetired { role }

RecoveryDisposition =
    Ineligible
  | Admitted { recovery: RecoveryTicket }

RecoveryDenialReason =
    RecoveryTicketsExhausted
  | RestartTimersExhausted
  | RestartLimitReached { active, requested, maximum }
  | ClockRegressed { previous, observed }
  | RecoveryCountExhausted { admitted }
  | ReleaseCalculationFailed { reason }

OperationalDiagnostic =
    WorkerPreparationFailed {
        trigger,
        prepared,
        reason,
        remaining,
    }
  | RecoveryDenied { trigger, stop, reason: RecoveryDenialReason }
  | ProxyCreationRejected { role, rejection }
  | ProxyInputRejected { role, input, reason }
  | ProxyOutcomeFailed { role, outcome }
  | ProxyDied { role, exit }
  | ProxyShutdownRejected { role, proxy, request, reason }
  | UnexpectedInput { input: FixedSupervisorEvent }
  | ForcedRetirement { role, residual, cause }

FactoryRejected is construction custody, not an operational diagnostic: the construction-only callable is consumed before a successful Behavior exists. WorkerPreparationFailed is emitted only after an operating recovery action returns its source. It retains the prepared prefix and untouched roles but not the reusable source authority.

Started and Restarted exist only after the exact atomic proxy-ready outcome. They expose the stable proxy capability and no worker recipient or worker evidence. Committed proxy creation, accepted proxy input, and a worker creation fact hidden inside the proxy cannot fabricate either event. The supervisor retains WorkerIncarnationEvidence privately for correlation. A replacement failure is never Restarted.

MemberRetired reports the durable topology change and carries only the role. The exact operational diagnostic emitted before the configured failure reaction is the sole owner of why retirement began. Repeating a summarized cause in the lifecycle value would create a second authority; labeling shutdown or deadline arrival as that cause would retain transition history rather than current topology. Forced actor-graph retirement remains a distinct runtime-custody diagnostic and does not fabricate MemberRetired.

RecoveryDenied is the sole observable owner of both the triggering stop and the exact denial reason. Repeating the reason in lifecycle output would create a second semantic cause. A rejected recovery therefore constructs no WorkerStopped lifecycle event: lifecycle owns ineligible and admitted stops; the operational diagnostic owns rejected recovery.

The Rust realization uses this one RecoveryDenialReason sum in restart admission and stores that same value with the complete triggering worker stop in RecoveryDenied. Public inspection borrows both values; a second private six-way sum or variant-for-variant diagnostic conversion is not part of the law. The post-denial topology retains a stop-less trigger and the unissued prepared workers separately. A later restart-schedule rejection is different: its diagnostic owns the rejected timer request, so topology continues to own the worker stop. Both paths use the same topology reaction only after that ownership distinction has been made.

If lifecycle publication is NotPublished, lifecycle events are not built and no discard operation occurs. Diagnostics always follow the selected disposition. DeliverTo emits one delivery; rejection becomes one terminal UndeliverableDiagnostic. Terminate emits the diagnostic directly to terminal settlement and selects Stop after preserving every other action in the turn. Neither path recursively diagnoses diagnostic rejection.

Required semantic action product

The governing solution names these fixed-supervisor lanes:

proxy_creations
proxy_creation_observations
proxy_stop_observations
proxy_install_inputs
proxy_replacement_inputs
proxy_shutdowns
worker_preparations
restart_schedules
lifecycle_events
management_replies
terminal_diagnostics
delivery_rejections

This is the semantic lane inventory, not a second interpretation-order specification. The generic ordering rule is owned by atomic-runtime-settlement.md: among the currently retained fixed-supervisor lanes, worker preparation precedes proxy operations, which precede restart scheduling, lifecycle publication, management replies, and diagnostics. Adding a missing lane must preserve that relative order and the creation-dependency rules above.

The oracle requires those operations plus a truthful representation of a route-delivered operational diagnostic. terminal_diagnostics can represent Terminate but cannot by itself represent DeliverTo(route), and lifecycle_events cannot own diagnostics because lifecycle publication is optional. Until an existing concrete product is proven to carry both choices without reinterpretation, the minimum model product treats this as one closed semantic lane:

diagnostics =
    Deliver { route, diagnostic }
  | Terminal { diagnostic }

delivery_rejections denotes the closed interpreter settlement product, not a catch-all message envelope. An input rejected by the supervisor becomes an OperationalDiagnostic::UnexpectedInput; rejection of an emitted action arrives through its lane-specific settlement. These are different laws.

This diagnostic-product mismatch is a falsification finding, not a production API amendment. A later executable task must reconcile the solution, matrix, retained-core decision, and research audit before adding a production lane.

The fold still returns the real Actions with its next behavior or terminal decision. Creation commits before same-action observations or proxy input. Within one recovery release, replacement inputs are emitted in declaration order. Diagnostics are emitted before a terminal verdict in the same action. The interpreter order and every accepted, rejected, or not-attempted settlement remain focused proof obligations.

Ownership table

ValueBefore acceptanceAfter action emissionRejection or final settlement
Initial definition and activationconstruction, then CreatingProxy or Starting(WaitingForAuthorization)proxy creation settlement, then exact install-input settlementreturned complete on factory/creation/input rejection; never reconstructed
Proxy reservationexact member statestaged creation and observation settlement share one scoped reservationconsumed by matching birth/exit result; collision never overwrites a route
Exact proxymember after committed proxy birthinputs and shutdowns borrow its delivery authority; member retains lifecycle ownershipmoves through exact stop or forced-transfer drain; never inferred from role
Activation slotfree capacity derived from member statesone operation ticket in a dispatched/awaiting statereleased only by matching atomic proxy outcome, rejected input, or forced drain transfer
Prepared replacementrecovery participantexact replacement-input settlementreturned on input rejection or transferred through drain; never cloned for retry
Recovery decisionlocal prepared candidate before admissioncommitted budget plus one exact RecoveryBatchpre-commit failure changes no peer; post-commit facts consume only matching participants
Timer requestrecovery batchrestart-schedule settlementrejected request remains diagnostic ownership; accepted timer is consumed once by exact input
Worker stopexact proxy reportrecovery owner, configured lifecycle event, diagnostic, or explicit publication omissionno second copy is retained to trigger another decision; shutdown moves only a stop still required by an unresolved failure path
Proxy reportexact child-source lifecycle inputlifecycle/diagnostic action or state transitionwrong source/kind moves complete into one unexpected-input diagnostic
Query routeone management requestone management-reply settlementrejection is owned by the supervisor host; it never becomes durable ownership
Lifecycle event routeselected definitionlifecycle-event settlementrejection cannot rewind readiness/recovery and transfers outward complete
Diagnostictransition-local valuediagnostic delivery or terminal settlementone terminal non-recursive outcome on rejection
Delayed prepared work at shutdownrecovery batchno later recovery action; it transfers into drain settlementlate timer is consumed stale and cannot revive the batch
Outstanding child draindraining fleetproxy shutdown/observation settlementexact stop closes once; deadline transfers residual ownership without fabricating stop

Transition notation

The matrices use these cells:

  • Q: emit the total status or capability reply and preserve state.
  • S0: close admission, cancel un-emitted recovery work, and enter one drain.
  • S=: shutdown is already active; preserve the drain and emit no duplicate shutdown or deadline request.
  • PB, PE, IS, PR, PS, RS, TF, DDS, DF, SET: apply the matching proxy-birth, proxy-exit, input-settlement, proxy-report, proxy-shutdown, restart-schedule, timer, drain-deadline-schedule, deadline, or lane-settlement rule.
  • F-: preserve the semantic state and emit exactly one complete unexpected-input diagnostic through the configured disposition.
  • NA: Stopped admits no mailbox input; late settlement belongs to the surviving lifecycle host.

All runtime-input cells require exact expected source, kind, operation, and correlation for admission. Every mismatch is F-. F- continues only under successful diagnostic delivery. Terminate or an undeliverable diagnostic preserves other actions and selects terminal settlement as specified above.

Total supervisor-mode matrix

ModeStatus queryCapability queryShutdownProxy birth/exitProxy input/reportRecovery timerDrain timerDelivery settlement
OperatingQQS0PB/PEIS/PR/PSRS/TFF-SET
DrainingQQS=PB/PEIS/PR/PSRS/TFDDS/DFSET
StoppedNANANANANANANANA

Queries remain available during orderly drain and show Stopping or Retired. DrainDeadline* in Operating and a recovery timer with no exact batch are F-. Late recovery facts during Draining settle or diagnose the cancelled exact batch but cannot emit a replacement.

Total operating-member matrix

Nested phase rules below exhaust each non-empty cell. The five Needs* row labels are readable projections of WorkerReplacement's stop/response product, not five separately stored Rust alternatives.

Owned member stateProxy birthProxy exitInput settlementInitial outcomeReplacement outcomeWorker stoppedUnavailable
CreatingProxyPBPEF-F-F-F-F-
CreatingProxyAfterExitPBF-F-F-F-F-F-
StartingF-PEISPRF-F-PR
OnlineF-PEF-F-F-PRPR
EmptyF-PEF-F-F-F-PR
RecoveryMember(AwaitingInitial)F-PEISPRF-F-PR
RecoveryMember(Waiting)F-PEF-F-F-PRPR
RecoveryMember(NeedsReceiptAndStop)F-PEISF-F-PRPR
RecoveryMember(NeedsReceipt)F-PEISF-F-F-PR
RecoveryMember(NeedsStopAndOutcome)F-PEF-F-PRPRPR
RecoveryMember(NeedsOutcome)F-PEF-F-PRF-PR
RecoveryMember(NeedsStop)F-PEF-F-F-PRPR
StoppingF-PEF-F-F-F-PR
RetiredF-F-F-F-F-F-F-

The exact proxy source is checked before report kind. A report from another owned role is foreign to this member and cannot be redirected by equal payload shape. An unowned application child never enters this matrix.

Initialization and proxy creation

Initialization reserves every ProxyReservation and pairs one affine initial OperationTicket with one private witness per role in declaration order before emitting the first creation. Each retained initial OperationInput owns that ticket. Pair allocation is fresh by construction: another reservation cannot collide with it, and process-wide allocation failure is not relabelled as a supervisor rejection. If any proxy-route reservation rejects, every locally paired operation is retired, the complete ordered initial set is returned, and no proxy creation, observation, input, or partial fleet is emitted. Otherwise one creation bundle per role contains:

  1. the fresh stable-proxy creation;
  2. exact creation observation;
  3. exact established-capability observation; and
  4. exact termination observation.

This is a Bombay staged-creation policy and a future real-boundary proof obligation, not a general actor-model guarantee.

An emitted proxy operation retains its private witness only until one exact settlement is admitted. Admission consumes the witness's correlation authority. An accepted settlement retains the operation ID only when a later exact proxy outcome requires it; a rejected, corrupt, or unattempted settlement already owns the complete operation and ID. Retaining the consumed witness beside that settlement would store arrival history rather than current authority. Foreign settlement admission returns the witness and complete settlement unchanged. Roster search attempts this affine admission in declaration order and restores every declined member to the same position without allocation or a separate owner query.

For an exact ProxyBirthResult:

  • Committed enters Starting(WaitingForAuthorization) with the exact proxy and retained initial input. It does not consume activation capacity merely because the proxy exists.
  • FoldRejected or HostRejected retains the complete initial input and applies the configured topology-failure reaction. RetireMember enters Retired because no proxy exists. StopSupervisor starts global drain.
  • In CreatingProxyAfterExit, rejection plus authoritative exit is one contradiction retaining both facts. Commit proves an installed but already terminal proxy and retires that role or begins whole-supervisor drain; it never sends the initial input.

An exact ProxyExit::BeforeBirth changes CreatingProxy to CreatingProxyAfterExit. An AfterBirth exit for the exact live proxy is handled by the stable-proxy-death reaction. RetireMember preserves the exact cause and removes only that role from live topology; StopSupervisor begins global drain. No worker failure is inferred from proxy death.

If proxy exit races an emitted initial or replacement operation, the exit atomically transfers that operation's input/report settlement to the surviving lifecycle host and releases its activation slot by transfer, not by pretending an atomic proxy outcome arrived. The affected participant leaves its recovery batch. The complete exit moves into the ProxyDied diagnostic settlement; the retired member retains only exact terminal correlation. Any later proxy report or rejected-report settlement meets that same host-owned exit and is returned as one contradiction retaining both facts. The actor does not clone the exit into state or forget the pending operation merely to retire quickly.

This host-transfer equation is required for totality but remains an open shared-settlement realization. An executable prototype must prove that the locked interpreter can perform the transfer; otherwise the focused finding is recorded rather than replaced by a mailbox flag.

After every transition that releases activation capacity, the supervisor scans waiting roles in declaration order. It reserves at most the remaining positive capacity and emits each eligible initial or replacement input in that same order. Reservation and emission are one commit.

Initial operation settlement and outcome

Authorization changes:

Starting(WaitingForAuthorization { input: { ticket, kind, control } })
    -> Starting(Dispatched { ticket, settlement })
       + proxy_install_inputs(control)
         whose source settlement owns { ticket, kind, control }

The complete input leaves state. The fold consumes its already-reserved ticket; authorization never performs a new fallible correlation allocation. Exact settlement then follows:

  • Accepted changes Dispatched to AwaitingOutcome; the operation ticket remains occupied.
  • Rejected releases the ticket and returns the exact input. It emits one ProxyInputRejected diagnostic and applies the configured failure reaction. There is no automatic retry.
  • A proxy outcome before accepted settlement is F-; the interpreter must discharge install settlement before making the later child report admissible.

In AwaitingOutcome, an exact InitialInstallation result releases the operation ticket:

  • Ready { worker } stores that opaque evidence in Online and, when selected, emits Started { role, proxy }.
  • Any complete non-ready result is retained inside ProxyOutcomeFailed, then applies RetireMember by draining the still-live proxy or begins whole-supervisor drain. It never emits Started.

An Unavailable report from the exact owned proxy is expected in every live non-retired member phase. It is relayed as one lifecycle event when publication is selected, preserving role, sender, proxy phase, and command. Without lifecycle publication, the same complete value is an operational diagnostic; it is never discarded. This is a deliberate model policy required to preserve the command obligation when no lifecycle consumer exists.

Recovery admission

Only an exact WorkerStopped from Online can trigger automatic recovery. It first produces the semantic Empty subject, then evaluates one transaction from the pre-transition fleet snapshot:

  1. classify the complete stop as normal or abnormal;
  2. apply permanent, transient, or temporary eligibility;
  3. select one-for-one, one-for-all, or rest-for-one roles in declaration order;
  4. reject every role already recovering, stopping, retired, or owned by an admitted replacement;
  5. include an initially unresolved role required by a coordinated strategy as AwaitingInitial rather than pretending it is ready;
  6. reserve one exact batch-preparation correlation, emit the typed ordered worker-preparation action, and enter the pending preparation phase;
  7. join its exact source settlement, retaining the source authority, every prepared submission, every selected role, and any rejection;
  8. reserve the recovery ticket, one operation ticket per selected replacement, and every fallible timer correlation;
  9. prune budget evidence at the interpreter-authored stop time using an inclusive window;
  10. reject clock regression explicitly;
  11. validate the complete multi-role budget charge;
  12. compute the checked one-based delay from the triggering role's next admitted RecoveryOrdinal; and
  13. commit the membership partition, prepared ownership, exact correlations, budget charge, and resulting actions in one transition.

Steps 1–5 are pure local preparation. Step 6 commits only the pending preparation phase and its action. Steps 8–13 occur only after the exact batch settlement succeeds. Failure changes no peer, emits no replacement, and charges no budget. The trigger's authoritative stop has still occurred; the configured failure reaction applies to that exact now-empty role.

Every selected replacement receives one new affine operation pair before the recovery commits. A pair cannot equal another live or retired pair. The complete ordered candidate set therefore has no operation-allocation rejection case; worker preparation, recovery/timer correlation, budget, and checked release remain the fallible pre-commit decisions.

The delay ordinal is deliberately the triggering role's admitted recovery ordinal. Selected peers do not combine their unrelated history into one delay. This fills a policy choice left implicit by the governing documents and must be compared before production work.

No source selects a reset rule. Bombay therefore preserves the triggering role's lifetime admitted count and advances it with checked arithmetic. Exhaustion is RecoveryCountExhausted { trigger, admitted }; it does not wrap, saturate, panic, reset implicitly, or masquerade as delay arithmetic overflow. This is a deliberate Bombay representation policy, not an actor-model guarantee.

Eligibility is total:

PolicyNormal stopAbnormal stop
Permanenteligibleeligible
Transientineligibleeligible
Temporaryineligibleineligible

Ineligible termination is not topology failure. The exact role remains Empty behind its live stable proxy and no recovery budget is charged. This is the AA-10 policy selected for the feature catalogue's previously open “retires or leaves empty” choice. It allows status to distinguish an intact but unavailable role from a lost proxy. Only explicit proxy/topology failure uses FailureReaction.

When lifecycle publication is configured, the exact ineligible stop moves into the role's WorkerStopped { disposition: Ineligible } event. The durable Empty role then owns no second stop. When publication is omitted, no lifecycle event is constructed and the explicit omission policy discharges the already classified stop. Empty retains no historical report merely for a later shutdown. Ineligibility is not an operational failure and therefore does not manufacture a diagnostic merely to dispose of the stop.

Selection is total:

  • one-for-one selects the triggering role;
  • one-for-all selects every restartable role in the immutable snapshot;
  • rest-for-one selects the trigger and every restartable role declared after it;
  • an online peer contributes its exact current worker;
  • the trigger contributes its exact stopped predecessor;
  • an initial operation that was already admitted may contribute one AwaitingInitial participant;
  • every other unresolved or terminal role is not restartable.

If a coordinated strategy requires an inadmissible role rather than one of the explicitly supported awaiting-initial phases, admission rejects the complete decision. It never silently shrinks the selected set.

Factory rejection identifies its role and returns every prepared peer definition. Budget denial reports active attempts, requested replacement count, and maximum. A maximum of zero denies every non-empty decision. Each admission appends one charge whose replacements equals participant count to the supervisor's BudgetState; the sum of active charge counts never exceeds the maximum. RecoveryBatch does not duplicate that evidence.

Recovery prerequisite transitions

Immediate timing starts in Ready. Delayed timing emits one exact schedule request for the batch. Schedule acceptance changes Scheduling to Waiting; rejection applies the topology-failure reaction to the trigger and returns every still-unemitted replacement. An exact timer input changes Waiting to Ready once. Stale, duplicate, wrong-generation, foreign, early, or regressing timer inputs are F-.

Replacement issue requires these three current truths:

  • its exact predecessor/readiness prerequisite is satisfied;
  • its batch release is Ready; and
  • activation capacity is currently available.

Readiness and timing remain satisfied in their owning participant and release state. Capacity is derived afresh and is consumed only in the transition that issues the input, so no stored phase claims a slot before issuance. That transition consumes the prepared input's already-reserved OperationTicket, emits the complete replacement input, and stores NeedsReceipt for a stopped participant or NeedsReceiptAndStop for an online participant. No fallible correlation allocation remains after batch admission. A batch may issue several newly eligible participants in one turn only up to available capacity, in declaration order.

An AwaitingInitial participant continues to process its exact InitialPhase:

  • accepted input settlement advances normally;
  • a ready initial outcome emits Started, supplies the exact predecessor, satisfies readiness, and may issue replacement in the same fold;
  • rejected input or non-ready atomic outcome cannot satisfy readiness. The participant leaves the batch and applies topology failure for that role;
  • the remaining admitted participants continue. Already emitted replacements are not rolled back, because atomicity governed admission, not cross-actor completion.

The recovery batch retires only after every participant has left through a ready replacement, typed failure reaction, shutdown transfer, or forced retirement. Its ticket is never reused.

Replacement settlement and outcome

For an exact NeedsReceiptAndStop or NeedsReceipt participant:

  • accepted settlement changes only the remaining requirements and retains its occupied operation ticket;
  • rejected settlement releases the ticket, retains the complete input in one diagnostic, and applies topology failure to that role without retry.

An exact WorkerStopped for the owned predecessor is accepted in NeedsReceiptAndStop, NeedsStopAndOutcome, or NeedsStop. It removes only the stop requirement, may emit the optional lifecycle event, and never opens or charges another recovery decision. A duplicate or stop for another worker is F-.

For an exact NeedsStopAndOutcome or NeedsOutcome participant:

  • every exact replacement outcome releases the activation ticket immediately;
  • if worker stop is already owned, Replacement::Ready { worker } leaves the recovery batch, enters Online, and optionally emits one Restarted carrying the exact proxy and recovery ticket;
  • if worker stop is still required, the complete result enters NeedsStop; readiness is not externally published until the matching stop report or its typed delivery settlement closes the join;
  • after the join closes, every rejection, activation failure, pre-ready stop, or contradiction applies topology failure and never emits Restarted;
  • an initial-installation report is wrong-kind even if its nested payload has the same worker type.

An exact WorkerStopped in NeedsStop closes the reunion and applies the retained outcome once. Rejection of the stop report delivery closes the same semantic join through lane settlement while preserving the rejected report with the lifecycle host; it cannot fabricate a successful stop event.

Operating recovery consumes a terminal WorkerReplacement immediately through one exhaustive replacement disposition. A ready outcome plus the exact stop is Restarted; a non-ready outcome plus the exact stop is ProxyFailed; an input rejection is InputRejected; every other current combination remains Waiting. This disposition is a transition result, never another stored member phase. It retains complete stop, outcome, or rejected-input ownership and chooses no diagnostic disposition, topology reaction, lifecycle route, or action. Shutdown retains the unchanged WorkerReplacement instead: retirement requires both proxy retirement and return of the emitted replacement input or outcome.

The transient terminal values preserve ownership explicitly. Restarted and ProxyFailed carry StoppedWorker { readiness, stop }; InputRejected carries RejectedReplacement { previous, readiness, stopped, operation, returned_worker }. The aggregate then consumes those values once. Success moves the successor's attempt/readiness into Online; predecessor readiness is discharged only after the exact stop has joined. Failure moves predecessor attempt/readiness into the selected member-retirement or supervisor-drain reaction. When lifecycle publication is configured, the exact stop moves into WorkerStopped; otherwise a failed replacement retains it with retirement ownership. There is no separate stop-presence flag or duplicated stop claim.

For successful replacement with lifecycle publication, WorkerStopped precedes Restarted in the declared lifecycle lane. Omitted publication constructs no lifecycle value. Input rejection and non-ready proxy outcome construct exactly one complete operational diagnostic and apply the configured topology reaction; neither can fabricate Restarted. Removing a terminal participant releases its operation occupancy and allows the existing declaration-order authorization transition to consider the next waiting participant in the same turn.

An exact spontaneous WorkerStopped opens a new recovery only in Online. While RecoveryMember::Waiting still owns an online participant, its first exact stop changes that participant to stopped and does not open another batch. A second stop while the member is empty or recovering is stale unless it is the one explicit replacement reunion above. A stop of an unrelated peer that remains independent and online may trigger its own disjoint batch.

Failure reaction

Every topology failure first constructs one exact diagnostic. Then:

  • RetireMember asks the exact live proxy to stop and enters Stopping; if no proxy was committed or it already exited, the member enters Retired directly. Shutdown settlement and exact proxy exit form one order-independent join. Accepted settlement retires its receipt; non-accepted settlement remains complete in the retired member after exact exit. Unrelated roles and disjoint recovery batches remain live.
  • StopSupervisor begins the same global drain as management shutdown after preserving the diagnostic in that action.

Factory rejection, budget denial, checked-delay failure, schedule rejection, proxy creation rejection, proxy input rejection, failed atomic proxy outcome, and stable-proxy death enter this equation. Ineligibility does not.

If diagnostic disposition is Terminate, it dominates RetireMember: the diagnostic action selects terminal settlement and the lifecycle host owns the remaining fleet drain. This is not silently converted into the configured topology reaction. A production realization must reconcile the actor's immediate stop verdict with exact child ownership before claiming this path is implemented.

Shutdown normalization

The first Shutdown atomically:

  1. closes management mutation and recovery admission;
  2. logically cancels every un-emitted prepared initial/replacement input;
  3. preserves emitted input settlement and atomic-outcome ownership;
  4. cancels delayed recovery batches so no later timer can issue work;
  5. transforms every member into one exhaustive drain member;
  6. emits at most one shutdown request for every exact installed proxy;
  7. retains every pending proxy creation until it resolves; and
  8. for deadline policy, reserves and emits one exact drain timer.

The drain partition is:

DrainMember =
    ResolvingProxyBirth {
        role,
        reservation: ProxyReservation,
        retained_initial,
        prior_exit: NoExit | Exited { exit },
    }

  | DrainingProxy {
        role,
        proxy: ProxyIncarnation,
        outstanding: ProxyOutstanding,
        phase: ProxyStopPhase,
    }

  | Drained {
        role,
        result: Graceful | Absent | Forced { residual },
    }

ProxyOutstanding =
    Idle
  | InitialWaiting { input: OperationInput }
  | InitialEmitted { ticket, settlement_or_outcome }
  | RecoveryWaiting { recovery, prepared }
  | ReplacementEmitted { recovery, ticket, settlement_or_outcome }

These variants own the complete values that were local at shutdown. There is no pending flag and no attempt to reconstruct an emitted input. Recovery batches dissolve into their per-proxy outstanding ownership plus cancelled timer settlement.

For ResolvingProxyBirth, exact rejection enters Drained(Absent) and creates no proxy. Exact commit emits one shutdown for the installed proxy and enters DrainingProxy. Commit after an authoritative pre-birth exit records a contradiction and counts the already terminal proxy drained; it cannot send to the dead proxy.

For DrainingProxy, shutdown settlement rejection stores the complete request and reason in ProxyStopPhase::Rejected while the exact exit observation remains live. It does not count as drained. An exact proxy exit consumes every outstanding operation through the child's typed drain settlement, preserves its complete result with the lifecycle host, and enters Drained(Graceful). The normal proxy report lane is not required to fabricate an initial or replacement outcome during child shutdown.

This exact child-drain settlement is a model requirement exposed by AA-01 and remains an open real-boundary proof obligation. If the interpreter cannot return emitted install/replacement ownership when the child suppresses normal parent reports during shutdown, later prototype work must record the focused kernel gap rather than drop the operation ticket.

Repeated shutdown is S=. It emits no duplicate proxy shutdown or deadline. Late restart timers and schedule settlements can settle cancelled requests but cannot restore a RecoveryBatch or emit replacement.

Deadline drain

DeadlinePhase =
    WaitingWithoutDeadline
  | Scheduling { timer, settlement }
  | Waiting { timer }
  | Fired { timer, observed_at }

WaitForActorGraph uses WaitingWithoutDeadline and may wait indefinitely. RetireActorGraphAfter uses exact interpreter-authored monotonic time. Wrong, duplicate, stale, early, or regressing deadline facts are F-.

Exact deadline-schedule acceptance changes Scheduling to Waiting. Exact rejection cannot silently weaken RetireActorGraphAfter into an unbounded wait. In the rejecting fold, every unresolved member moves to Drained(Forced { residual }); the residual preserves the complete rejected request, timer correlation, capability reason, and every other outstanding ownership claim. The rejection is the forced-retirement cause and transfers directly to the surviving lifecycle host. Any operational diagnostic follows the selected disposition independently; its delivery cannot gate or undo the forced transfer.

When the exact deadline fires, the aggregate atomically selects forced retirement for every unresolved DrainMember. Its terminal ownership must contain the role, proxy or reservation, current semantic phase, every outstanding operation/timer/action settlement, and cause. The implementation may project this as Drained(Forced { residual }) per member or retain the complete stopped supervisor plus its exact deadline cause; it must not store both. Ownership transfers to the surviving lifecycle host. No accepted shutdown, proxy exit, worker readiness, successful restart, or normal lifecycle event is fabricated.

The supervisor selects normal actor termination only when every member is Drained and every action in the final transition has a settlement owner. A forced actor-graph summary is not the application result: the live root remains in residual settlement until late activation, proxy, and delivery ownership resolves.

Unrelated application children and application births never enter DrainingFleet, are never queried, and are never stopped by this actor.

Stale, overlap, and contradiction laws

  • A proxy birth or exit advances only the role owning its exact reservation or installed capability.
  • An install/replacement settlement advances only its exact role, proxy, operation ticket, and expected dispatched phase.
  • An atomic proxy report advances only the exact child source and expected operation kind. Nested payload similarity cannot substitute for kind.
  • A duplicate report after its operation ticket released is rejected and cannot release another slot.
  • A worker stop outside Online cannot start recovery.
  • One role cannot join two recovery batches. Overlap rejects the new complete decision before factory results, budget, or peers commit.
  • A timer fact advances only its exact recovery ticket and timer generation.
  • Proxy creation rejection plus authoritative exit is a contradiction retaining both facts. Commit plus prior exit retires the exact dead proxy.
  • A report claiming readiness from a proxy already authoritatively stopped is a contradiction, never a transient Started/Restarted.
  • A delivery rejection cannot roll back an already committed member or budget transition. Its lane-specific payload moves to settlement.
  • Diagnostic delivery rejection is terminal and non-recursive.
  • No stale or contradictory input is consumed merely to make a later fact easier to accept.

Feature-catalogue trace

Requirement familyModel evidence
FS-BUILDconstruction domain, non-empty unique role order, common protocol, optional lifecycle publication
FS-TOPOLOGYnormalized state, independent-member sum, exact proxy creation, activation occupancy derived from operation states
FS-FACTScomplete proxy lifecycle input, operating-member matrix, predecessor stop/outcome join, stale and contradiction laws
FS-OPERATEtotal status/capability projection, distinct query/lifecycle/diagnostic routes
FS-ELIGIBILITYcomplete permanent/transient/temporary table and selected intact-proxy Empty policy
FS-STRATEGYimmutable snapshot, ordered selection, awaiting-initial participant, disjoint overlap law
FS-BUDGETpre-commit pruning, inclusive window, atomic counted charge, zero maximum, clock regression
FS-TIMINGexact timer settlement, trigger ordinal, checked delay, eight-state prerequisite sum
FS-ATOMICITYtwelve-step recovery preparation and one batch/budget commit
FS-FAILUREexact operational diagnostic followed by RetireMember or whole-supervisor drain
FS-SHUTDOWNnormalized drain partition, pending creation, emitted-operation transfer, exact shutdown rejection, deadline residual

Every family remains a model claim, not implementation or verification status. Open shared settlement, diagnostic, activation, terminal-lift, and deadline mechanisms keep their dependent production coverage rows open.

Independent-model obligations

AA-10 defines the oracle structure for later tests. The executable model must not copy the implementation branch structure. It should use independent vocabulary such as roster cells, admitted recovery batches, occupied permits, and drain obligations, then compare complete traces.

At minimum later tasks must cover:

  • empty and duplicate-role construction rejection;
  • initial proxy creation in declaration order and partial-preparation failure;
  • proxy exit before/after birth resolution;
  • positive activation bounds of one and two with declaration-order release;
  • foreign, duplicate, and stale initial or replacement operation IDs, including proof that every new operation pair differs from every earlier pair;
  • accepted and rejected install settlement before atomic proxy outcome;
  • total query projections in every member phase;
  • lifecycle and capability projections that expose only the stable proxy as a service capability;
  • permanent/transient/temporary eligibility for normal and abnormal stops;
  • one-for-one, one-for-all, and rest-for-one selection from immutable snapshots;
  • unresolved-initial participants and overlapping failure rejection;
  • zero budget, inclusive window boundary, pruning, multi-role atomic charge, and clock regression;
  • immediate, constant, linear, and exponential timing, checked overflow, and all eight readiness/timer/authorization gates;
  • factory rejection at every selected position with no peer mutation;
  • stale/duplicate/foreign report, timer, exit, and settlement facts;
  • lifecycle omitted versus delivered and both diagnostic dispositions;
  • shutdown from every member phase, creation/exit ordering, rejected child shutdown, rejected deadline scheduling, late timers, and forced residual transfer; and
  • complete named actions and accepted/rejected interpreter settlement.

First-slice non-features and open findings

AA-10 intentionally does not provide:

  • Rust supervisor, fleet, recovery, builder, protocol, event, or effect types;
  • an executable fold or independent model implementation;
  • a shared recovery framework or reuse of dynamic-supervisor/pool state;
  • proxy-private worker creation, initialization, activation, or worker routing;
  • an interpreter for activation capacity, delivery settlement, timers, diagnostics, deadlines, or residual root ownership;
  • wrapper-composition, initialization-order, compiler/DevX, or migration proof;
  • a capability-safe heterogeneous public-protocol supervisor; or
  • edits to the locked kernel, legacy actors, macros, testkit, or runtime.

The model records four findings requiring later comparison:

  1. the governing documents leave ineligible fixed members “retired or empty” without a selected construction policy; this oracle deliberately leaves an intact live proxy Empty;
  2. delayed coordinated recovery does not state which member history determines its one-based delay; this oracle uses the triggering role's admitted recovery ordinal;
  3. the named fixed-supervisor effect product has terminal diagnostics but no explicit route-delivered diagnostic operation even though lifecycle publication is optional; and
  4. normal proxy death or shutdown with an emitted install/replace operation requires a typed child terminal/drain settlement that returns outstanding ownership even when no normal proxy outcome can reach the supervisor.

These are falsification results, not changes to production authority. Before an executable task relies on any new mechanism, the solution, matrix, retained-core decision, and research audit must be reconciled together or the existing real boundary must be proven to express the same law unchanged.

This blocked specification may be compared with the independent dynamic supervisor, FIFO pool, and keyed pool models, but no comparison may treat its child-terminal settlement requirement as implemented or extract machinery from that assumption. It does not make AA-11 eligible: executable fixed supervision depends on AA-07's completed proxy boundary audit and eventual AA-10 closure.

Dynamic-supervisor falsification model

Status and authority

This document is the AA-20 independent semantic model for one dynamic supervisor. It is a non-production falsification oracle. It does not select Rust types, define another behavior algebra, implement a supervisor, or mark a production coverage row implemented. docs/engineering/atomic-actor-solution.md remains the production design authority.

Fresh allocation is the actor-model law used here: every accepted entry owns a fresh stable proxy, and every worker behind that proxy is a fresh actor. Creator-local creation correlations, exact capability settlement, operation tokens, generation-safe key reuse, activation authorization, and actor-graph drain are Bombay derivations or policy choices. Bounded keyed membership, explicit management operations, one durable lifecycle owner, unexpected-exit handling, and phase-sensitive cancellation are dynamic-supervisor template laws.

Runtime route selection is owned normatively by docs/atomic-runtime-settlement.md. An accepted start issues and stores one CreationId for its proxy; it never chooses or stores a runtime route before emitting CreateChild. The generic creation settlement returns that exact correlation and every rejected value. There is no separate route request, waiting state, public route, or dynamic-supervisor-specific creation result.

The model is deliberately not a fixed supervisor with an optional role list. It contains no worker factory, fixed roster, restart eligibility, restart strategy, restart budget, or backoff policy.

The model must falsify designs that make any of these claims false:

  1. The configured positive entry limit bounds every retained entry, including entries still creating, cancelling, draining, or retiring.
  2. A semantic key is management identity only. It is never converted into a proxy route, nonce, incarnation, or proof of freshness.
  3. Every accepted start reserves one fresh entry generation, proxy creation ID, cancel authority, and initial-operation correlation before commitment.
  4. Admission and realization are distinct. StartAccepted and ReplaceAccepted never claim readiness.
  5. The stable proxy is the only externally routable service capability. Worker incarnation evidence is opaque and non-routable.
  6. At most one management mutation owns an entry at a time. Every submitted worker definition is either locally owned, transferred once, returned once, or held by exact settlement ownership.
  7. Request reply routes are temporary. One mandatory durable lifecycle route owns later realization, unavailability, cancellation completion, and retirement facts.
  8. Cancellation is exact and phase-sensitive. It cannot claim that emitted creation, delivery, initialization, or activation work was physically cancelled.
  9. Removing an entry releases capacity only after every exact outstanding fact and action settlement transfers or resolves. Reusing its key receives a fresh generation and fresh proxy creation ID.
  10. Stale, duplicate, foreign, wrong-generation, wrong-operation, wrong-kind, and contradictory inputs cannot mutate a current entry.
  11. Query is a total read-only semantic projection and never exposes private definitions, routes, tokens, or proxy-private phases.
  12. Global shutdown closes mutation and drains every retained or still-creating entry exactly once while preserving request, lifecycle, diagnostic, and residual ownership.
  13. Every accepted input produces one next state and one complete named action product. No effect is ambient.

“Atomic” means one local Behavior fold commits one supervisor state and its complete Actions. It does not claim atomic delivery, creation, cancellation, or work across actors.

Model vocabulary

The following names describe the oracle. They are not proposed public Rust names.

Key = application-authored semantic management key
EntryGeneration = fresh non-reused supervisor correlation for one accepted key use
EntryIdentity = { key, generation: EntryGeneration }

ProxyBirthAttempt = fresh non-reused CreationId issued by the supervisor
RoutedCreation = the existing interpreter-private route selected for that CreationId
ProxyIncarnation = externally routable exact capability for one committed stable proxy

WorkerIncarnationEvidence = opaque non-routable provenance for one installed worker
WorkerSubmission = complete owned worker definition and activation work for one attempt

OperationKind = Start | Replace
OperationCorrelation = fresh non-reused checked operation identity and admission order
CancelAuthority = opaque caller-held capability for one OperationCorrelation
OperationEvidence = opaque non-cancelling projection used in durable events
ProxyOperationWitness = private affine authority retained before one emitted
    proxy input settles
ProxyOperationId = opaque affine correlation returned only after that exact
    proxy input is accepted

PreparedProxyInput =
    Initial { worker: WorkerSubmission }
  | Replacement { worker: WorkerSubmission }

DefinitionOwnership = Present { worker: WorkerSubmission } | Transferred

StopCorrelation = fresh non-reused correlation for one explicit entry stop
ShutdownCorrelation = structural exact { EntryIdentity, ProxyIncarnation }
DeadlineCorrelation = { timer, generation }

Key, EntryGeneration, operation correlations, proxy-operation IDs, attempts, timer generations, and child routes are correlation—not actor identity. Only a committed creation yields ProxyIncarnation. Sequence arithmetic, address reuse, key equality, timing, or adjacency cannot manufacture provenance.

The proxy alone retains its routable worker recipient. The dynamic supervisor retains only WorkerIncarnationEvidence for exact replacement and stop correlation. Status, capabilities, request replies, and lifecycle events never grant a route around the stable proxy.

Every checked sequence has an explicit exhaustion outcome and never wraps. Collision against retained state is a controlled contradiction, not an invented result of the opaque StableProxy operation pair. Failed correlation issue returns every still-owned input and commits no entry, operation, activation occupancy, or action.

Construction domain

One complete construction contains:

DynamicDefinition = {
    entry_limit: PositiveMaximum,
    activation: ActivationContract,
    activation_limit: PositiveMaximum,
    unexpected_exit: KeepEmpty | Retire,
    actor_drain: ActorDrainPolicy,
    lifecycle: DurableLifecycleRoute,
    diagnostics: DeliverTo { route } | Terminate,
}

The durable lifecycle route is mandatory and selected once. It preserves its concrete logical, established, or mixed capability form and static hosting obligations. No request route can replace it. Diagnostics are independently mandatory through either a concrete route or terminal settlement.

ActivationContract is the selected static interpretation law. Each WorkerSubmission is the complete owned per-attempt definition and activation work after that law is applied. The fold never reconstructs, looks up, or clones an affine activation plan after admission.

A zero entry limit, zero activation limit, invalid deadline, or missing policy is a construction failure. There is no fixed factory, worker roster, recovery policy, callback, no-op route, default unexpected-exit behavior, or public structural path.

A closed heterogeneous worker sum is valid only when every variant exposes one common concrete public service protocol. Different public protocols require different dynamic supervisors; the model never erases them into one envelope.

AA-20 selects no builder, typestate spelling, public enum names, or macro.

Supervisor state

SupervisorState =
    Operating {
        definition,
        entries: BoundedEntryTable,
        allocators,
    }
  | Draining {
        definition,
        entries: BoundedDrainTable,
        deadline: DeadlinePhase,
        allocators,
    }
  | Stopped

BoundedEntryTable contains at most entry_limit entries. Every key occurs at most once. Every entry stores its exact generation and proxy creation ID or exact proxy; the table does not derive either from the key.

The table need not retain declaration order. Activation fairness is explicit: each waiting start or replacement already stores its ordered OperationCorrelation, and newly available capacity issues the lowest outstanding operation first. There is no separately mutable queue whose contents can disagree with entry phases.

Activation occupancy is derived from exact dispatched or awaiting proxy-input states. A prepared but un-emitted input owns its complete worker submission but does not occupy activation capacity. Reserving capacity, forming the infallible proxy-operation pair, and emitting the prepared input are one transition.

Transaction-local start preparation

Start preparation is not a stored entry phase:

PreparedStart = {
    identity: EntryIdentity,
    creation: CreationId,
    operation: OperationCorrelation,
    cancel: CancelAuthority,
    input: PreparedProxyInput,
}

PreparedReplace = {
    identity: EntryIdentity,
    proxy: ProxyIncarnation,
    base: ReplaceBase,
    operation: OperationCorrelation,
    cancel: CancelAuthority,
    input: PreparedProxyInput,
}

For one Start, the supervisor checks shutdown, duplicate key, and table capacity; then fallibly reserves every field above before committing anything. Failure returns the complete worker and an exact reason. Success commits Entry::Starting(CreatingProxy) and emits the acceptance reply, fresh empty proxy creation, exact creation observation, and exact proxy-exit observation in one action.

There is therefore no observable stored Reserved phase between acceptance and creation emission. A future executable design that introduces such a phase must identify the real intervening settlement or prerequisite. A label that is only a transient local preparation value must not appear in public query.

Operating entry sum

Every retained entry is exactly one of:

Entry =
    Starting(StartEntry)
  | Ready(ReadyEntry)
  | Empty(EmptyEntry)
  | Replacing(ReplaceEntry)
  | Stopping(StopEntry)
  | Cancelling(CancelEntry)
  | Retiring(RetireEntry)

No entry has pending, ready, cancelled, stopping, or retired flags.

Start entry

StartEntry =
    CreatingProxy {
        identity,
        creation: CreationId,
        operation,
        input: PreparedProxyInput,
    }
  | WaitingForAuthorization {
        identity,
        proxy: ProxyIncarnation,
        operation,
        input: PreparedProxyInput,
    }
  | AwaitingInputReceipt {
        identity,
        proxy: ProxyIncarnation,
        operation,
        witness: ProxyOperationWitness,
    }
  | AwaitingOutcome {
        identity,
        proxy: ProxyIncarnation,
        operation,
        proxy_input: ProxyOperationId,
    }

CreatingProxy and WaitingForAuthorization own the worker inside the prepared input. AwaitingInputReceipt retains only correlation; the input has moved to source-side delivery settlement. AwaitingOutcome exists only after exact input acceptance.

Available entries

ReadyEntry = {
    identity,
    proxy: ProxyIncarnation,
    worker: WorkerIncarnationEvidence,
    last_operation: TerminalOperation,
}

EmptyEntry = {
    identity,
    proxy: ProxyIncarnation,
    previous: WorkerIncarnationEvidence,
    cause,
    last_operation: TerminalOperation,
}

TerminalOperation =
    Committed { operation: OperationCorrelation, kind: OperationKind }
  | Cancelled { operation: OperationCorrelation, kind: OperationKind }
  | None

At most one terminal operation is retained per entry. It makes an immediate matching repeated cancel truthful without an unbounded operation-history table. Accepting the next start/replace mutation retires the prior terminal record; older authorities then produce CancellationReceipt::Stale. This is a deliberate bounded-retention policy, not an actor-model rule.

Replacement entry

ReplaceBase =
    WasReady { worker: WorkerIncarnationEvidence }
  | WasEmpty { previous: WorkerIncarnationEvidence, cause }

ReplaceEntry =
    WaitingForAuthorization {
        identity,
        proxy,
        base: ReplaceBase,
        operation,
        input: PreparedProxyInput,
    }
  | AwaitingInputReceipt {
        identity,
        proxy,
        base: ReplaceBase,
        operation,
        witness,
    }
  | AwaitingOutcome {
        identity,
        proxy,
        base: ReplaceBase,
        operation,
        proxy_input,
    }

StableProxy is the sole owner of predecessor drain. It does not publish a replacement outcome until its internal predecessor shutdown/exit reunion has closed, and its owner never reconstructs that outcome from lower-level worker events. DynamicSupervisor therefore owns no predecessor-stop phase. The replacement outcome's nested replaces evidence must equal the retained base; that validation is the supervisor's only predecessor responsibility after input transfer.

Explicit stop entry

StopOrigin =
    Available { prior: ReadyEntry | EmptyEntry }
  | Starting { phase: StartOutstanding }

StopEntry =
    WaitingForProxyBirth {
        identity,
        creation: CreationId,
        stop: StopCorrelation,
        start_outstanding,
    }
  | ShutdownDispatched {
        identity,
        proxy,
        stop,
        origin: StopOrigin,
        shutdown: ShutdownCorrelation,
        settlement,
    }
  | AwaitingProxyExit {
        identity,
        proxy,
        stop,
        origin: StopOrigin,
        shutdown: ShutdownCorrelation,
    }
  | ExitBeforeShutdownSettlement {
        identity,
        proxy,
        stop,
        origin: StopOrigin,
        exit,
        shutdown: ShutdownCorrelation,
    }

Stop during a pending start is accepted and waits for exact proxy creation. It is not operation-token cancellation: it closes the complete entry by key, reports stop admission to its caller, and transfers the interrupted start obligation to the durable lifecycle owner. Stop during replacement or cancellation is rejected as unavailable and does not steal that operation.

Cancellation entry

CancelKind = Start | Replace { base: ReplaceBase }

CancelEntry =
    AwaitingProxyBirth {
        identity,
        creation: CreationId,
        operation,
        kind: Start,
        definition_disposition: ReturnedToCancelReply,
    }
  | DrainingProxy {
        identity,
        proxy,
        operation,
        kind: CancelKind,
        outstanding: CancelOutstanding,
        shutdown: ProxyStopPhase,
    }

CancelOutstanding =
    NoTransferredInput
  | InputSettlement { witness: ProxyOperationWitness, settlement }
  | ProxyOutcome { proxy_input: ProxyOperationId }
  | OutcomeBeforeExit { outcome }

ProxyStopPhase =
    NotEmitted
  | ShutdownDispatched { shutdown, settlement }
  | AwaitingExit { shutdown }
  | Rejected { shutdown, request, reason }
  | ExitObserved { exit }

StartOutstanding =
    DefinitionLocal { operation, input }
  | InputEmitted { operation, witness: ProxyOperationWitness, settlement_or_outcome }

RetireOutstanding =
    Idle
  | Start { outstanding: StartOutstanding }
  | Replace { operation, base, witness: ProxyOperationWitness, settlement_or_outcome }
  | Cancellation { operation, outstanding: CancelOutstanding }
  | Stop { stop, settlement_or_exit }

Cancellation before proxy-input emission returns the complete submitted worker through CancellationReceipt::Returned. If proxy creation is already in flight, the entry still waits for its exact result; a late committed proxy is drained.

Cancellation after input emission returns CancellationReceipt::Pending. It never returns the worker, even if later delivery rejection transfers that input to the lifecycle host. A late ready result is retained only for drain and never emits Started or Replaced.

Retirement entry

RetireCause =
    UnexpectedWorkerExit
  | StableProxyExit
  | StartFailed
  | ReplacementFailedAfterTopologyLoss
  | Cancellation
  | Stop
  | DiagnosticTermination

RetireEntry = {
    identity,
    proxy: NoProxy | Pending(CreationId) | Exact(ProxyIncarnation),
    cause: RetireCause,
    outstanding: RetireOutstanding,
    shutdown: ProxyStopPhase,
}

An entry is removed only when outstanding is empty and its proxy is rejected before birth or authoritatively exited. Removal is a state transition, not a permanent tombstone.

Public command sum

Management =
    Start { key, worker, reply_to }
  | Replace { key, worker, reply_to }
  | Stop { key, reply_to }
  | Query { key, reply_to }
  | Cancel { authority: CancelAuthority, reply_to }

Here worker means the complete WorkerSubmission, not merely the inner behavior after its activation work has been separated. A future Rust surface may infer and hide that product, but its ownership cannot disappear.

AA-20 omits a separate Retire command. For a ready or empty entry, explicit Stop already drains the stable proxy and releases the key after exact exit. Retirement after unexpected exit is policy-driven and automatic. Adding Retire without another state-transition law would create two public ways to perform the same operation.

Every request route is used once for its immediate reply and then moves to action settlement. It is never stored as the durable lifecycle owner. A CancelAuthority is returned in every cancel reply (or its rejected-delivery settlement), so the supervisor never retains or clones that affine authority.

Request receipts

WorkerChangeReceipt = { key, cancel: CancelAuthority }
WorkerChangeRejection<Reason> = { key, worker, reason: Reason }

Start result =
    Result<WorkerChangeReceipt, WorkerChangeRejection<StartRejection>>

Replace result =
    Result<WorkerChangeReceipt, WorkerChangeRejection<ReplaceRejection>>

Stop result = Result<Key, StopRejection<Key>>

CancellationReceipt =
    Returned { authority, worker }
  | Pending { authority, phase }
  | Committed { authority, resulting_phase }
  | Cancelled { authority }
  | Stale { authority }
  | Draining { authority }

QueryReply = Unknown { key } | Known { key, phase }

Start rejection reasons include AlreadyExists, AtCapacity, ShuttingDown, entry-generation exhaustion, management-operation exhaustion, and proxy-creation exhaustion. Replace rejection includes unknown, unavailable, shutting down, and management-operation exhaustion. Every rejection owns the complete submitted worker. Stop rejection includes unknown, unavailable, already stopping, shutting down, and stop-correlation exhaustion or collision; no stop state or shutdown action is committed when that reservation fails.

Public query projection

PublicPhase =
    CreatingProxy
  | WaitingForActivationAuthorization
  | AwaitingProxyOutcome
  | Ready { proxy: ProxyIncarnation }
  | Empty
  | Stopping
  | Replacing
  | Cancelling
  | Draining
  | Retiring

Query is a byte-for-byte semantic no-op on entry state, allocator state, capacity, and activation occupancy. It exposes no worker definition, child route, entry generation, proxy-operation correlation, cancel authority, proxy-private installation phase, or worker recipient. Delayed lifecycle events retain the opaque entry generation because they cross key reuse; an immediate query does not expose bookkeeping its caller cannot use. During global shutdown it projects the drain phase. Absence is Unknown, not an Option combined with flags.

Durable lifecycle and diagnostic values

DynamicLifecycle =
    Started { identity, operation: OperationEvidence, proxy: ProxyIncarnation }
  | StartFailed {
        identity, operation: OperationEvidence,
        definition: DefinitionOwnership, reason,
    }
  | Replaced { identity, operation: OperationEvidence, proxy: ProxyIncarnation }
  | ReplacementFailed {
        identity, operation: OperationEvidence,
        definition: DefinitionOwnership, reason,
    }
  | StopFinished {
        identity,
        proxy,
        result: Result<ProxyExit, StopFailure>,
    }
  | UnexpectedWorkerStopped {
        identity, observed_at, disposition: KeptEmpty | Retiring,
    }
  | OperationCancelled { identity, operation: OperationEvidence, kind, result }
  | WorkerChangeInterrupted {
        identity,
        operation: OperationEvidence,
        interruption:
            ExplicitStop { stop: OperationEvidence }
          | SupervisorShutdown { change: Start | Replacement },
        definition: DefinitionOwnership,
    }
  | CommandUnavailable { identity, sender, proxy_phase, command }
  | EntryRetired { identity, cause }

DynamicDiagnostic =
    CorrelationReservationRejected { key, operation_kind, reason }
  | ProxyCreationRejected { identity, rejection }
  | ProxyInputRejected { identity, operation, input, reason }
  | ProxyOutcomeFailed { identity, operation, outcome }
  | ProxyShutdownRejected { identity, proxy, request, reason }
  | StableProxyDied { identity, proxy, exit }
  | RejectedLifecycleFact { rejected }
  | ForcedRetirement { identity, residual, cause }

Lifecycle events never expose a routable worker recipient. Exact predecessor evidence from a worker-stop report moves into the entry; the durable event gets the disjoint observation time and semantic disposition. Service capability publication is limited to the stable proxy. A failure or interruption carries a still-local worker definition as Present; after proxy-input emission it says Transferred and the exact input settlement remains the sole owner. Every event delivery has exact settlement ownership; delivery rejection cannot roll back admission or realization.

When one transition emits both lifecycle and diagnostic values, the exact source payload moves to only one of them. The other receives an explicit semantic classification or a disjoint field projection. The model never clones an affine rejection, exit, worker definition, command, or incarnation fact merely to satisfy two consumers.

Diagnostics follow DeliverTo(route) | Terminate. Diagnostic delivery rejection is terminal and non-recursive. Lifecycle and diagnostics are independent lanes: neither substitutes for the other. Terminate transfers the diagnostic and every still-live entry obligation to the surviving lifecycle host and enters the same global drain equation; it does not drop the diagnostic or continue an ordinary entry-local transition.

Stable-proxy input sum

ProxyCreationResult = the generic CreationsSettled result for the exact
    CreationId and StableProxy creation

ProxyInputResult = ActionItemResult<
    ProxyOperation,
    ProxyInputReceipt { creation, proxy, operation: ProxyOperationId },
    ProxyInputRejection,
    Never,
>

ProxyReport =
    Initial { outcome }
  | Replacement { outcome }
  | WorkerStopped { stop, observed_at }
  | Unavailable { sender, phase, command }

ProxyExit = { identity, proxy, exit }

ProxyShutdownSettlement =
    Accepted { identity, proxy, shutdown }
  | Rejected { identity, proxy, shutdown, request, reason }

The generic result owns whether interpretation was attempted. Acceptance owns only the receipt promised by the request. Rejection and corruption return the complete ProxyOperation; an unattempted result retains it unchanged. There is no supervisor-specific result sum or conversion seam.

Every proxy report is accompanied by its exact child-source capability. The entry generation, exact source, expected operation kind, and replacement outcome's nested replaces evidence form complete correlation. The supervisor does not widen AA-01's proxy protocol with its cancel authority.

The source carried by a proxy input result or proxy exit selects its entry once before the phase matrix. A source that selects no entry is returned as rejected input. After selection, the phase checks only its distinct operation or worker evidence; it does not compare the selecting source with itself again or invent a second phase-local wrong-source outcome.

Required semantic action product

The minimum model product is:

proxy_creations
proxy_creation_observations
proxy_stop_observations
proxy_initial_inputs
proxy_replacement_inputs
proxy_shutdowns
management_replies
lifecycle_events
diagnostics = Deliver { route, diagnostic } | Terminal { diagnostic }
deadline_schedules
rejected_inputs
delivery_settlements

All operations are named semantic lanes. No positional traversal, nested .inner, runtime registry, dynamic envelope, callback, or direct effect occurs inside the fold. The actual production product may use existing lower-order lanes only if it proves this complete observable algebra without reinterpretation.

Ownership table

ValueActor-side owner before emissionSettlement/host owner after emissionTerminal law
Start workerprepared start, then creating/waiting entryproxy-input settlement after emissionreturned only before transfer; otherwise lifecycle host settles it
Replace workerprepared replace in waiting entryreplacement-input settlement after emissionsame phase boundary as start
Entry generationexact retained entrynever emitted as authorityretired only when entry removal closes all facts
Cancel authorityaccepting callermoved into one cancel requestevery reply or rejected-delivery settlement returns it; the supervisor never retains it
Operation correlationactive entrylifecycle/diagnostic settlement after terminal realizationat most one bounded terminal record remains
Stable proxyentry after committed birthactions borrow delivery authority; lifecycle host retains ownershipexact exit or forced transfer retires it
Worker evidenceentry or replacement joinnever a routable action capabilityreplaced by fresh evidence or retired with exact stop
Activation slotderived from dispatched/awaiting statehost owns unresolved proxy input/outcomematching outcome, input rejection, or forced transfer releases it
Request replyincoming commandrequest-delivery settlementnever becomes durable lifecycle ownership
Lifecycle eventtransition-local valuelifecycle-delivery settlementrejection transfers outward without state rewind
Diagnostictransition-local valuediagnostic route or terminal settlementrejection is terminal and non-recursive

Management-command matrix

Entry phaseStart same keyReplaceStopCancel matching active opQuery
absentadmit if capacity and preparation succeedreject/return workerreject unknownunknown/staleUnknown
Starting::CreatingProxyreject/return workerreject/return workeraccept and wait birthreturn worker, wait birthCreatingProxy
Starting::WaitingForAuthorizationreject/return workerreject/return workeraccept and drain proxyreturn worker, drain proxywaiting authorization
Starting::AwaitingInputReceiptreject/return workerreject/return workeraccept and drain outstandingpending cancellationawaiting outcome
Starting::AwaitingOutcomereject/return workerreject/return workeraccept and drain outstandingpending cancellationawaiting outcome
Readyreject/return workeradmit replacementaccept stopmatching last op committedready capability
Emptyreject/return workeradmit replacementaccept stopmatching last op terminalempty
Replacing::WaitingForAuthorizationreject/return workerreject/return workerreject unavailablereturn replacement, restore basereplacing
emitted/awaiting replacementreject/return workerreject/return workerreject unavailablepending cancellationreplacing
Stoppingreject/return workerreject/return workerreject already stoppingactive start/replace token is shutdown-ownedstopping
Cancellingreject/return workerreject/return workerreject unavailablealready cancelledcancelling
Retiringreject/return workerreject/return workerreject unavailableshutdown-owned or staleretiring

During global drain, every mutation rejects with ShuttingDown; Cancel returns CancellationReceipt::Draining; Query remains total.

Lifecycle-fact matrix

Notation:

  • A accepts the exact fact and performs the named phase transition;
  • J accepts one side of an order-independent join;
  • D settles only the matching drain obligation;
  • F preserves state and emits one complete rejected-fact diagnostic.

Exact entry generation and proxy source are checked before this table. A fact that fails either check is always F.

Entry phaseProxy birthProxy exitInput settlementInitial outcomeReplacement outcomeWorker stopUnavailableShutdown settlement
Starting::CreatingProxyAAFFFFFF
Starting::WaitingForAuthorizationFAFFFFAF
Starting::AwaitingInputReceiptFAAFFFAF
Starting::AwaitingOutcomeFAFAFFAF
ReadyFAFFFAAF
EmptyFAFFFFAF
Replacing::WaitingForAuthorizationFAFFFAAF
Replacing::AwaitingInputReceiptFAAFFFAF
Replacing::AwaitingOutcomeFAFFAFAF
StoppingA or F by originJDDDDAJ
CancellingDDDDDDAD
RetiringDDDDDDAD
global DrainEntryDDDDDDDD

WorkerStopped while replacement still waits for authorization changes a WasReady base into the exact empty predecessor; it does not open an unexpected-exit policy decision or a second operation because the accepted replacement already owns the service mutation. For WasEmpty, another stop is F. After replacement input transfer, StableProxy consumes predecessor stop privately and emits only the completed replacement outcome. A later WorkerStopped report can describe only the successor selected by that completed outcome and is processed after the replacement result.

Stopping accepts proxy birth only when its origin still owns the matching pending proxy creation. Input and outcome values in stopping/cancelling/ retiring states never publish success; they settle exact outstanding ownership through the drain equation.

Start transitions

Successful preparation commits the entry before emitting StartAccepted and the proxy creation bundle. Acceptance delivery rejection cannot unreserve the entry or recover the worker; the durable lifecycle owner remains authoritative for later realization.

The entry retains only OperationCorrelation. CancelAuthority moves to the request reply action and then to its delivery settlement; the supervisor never stores or clones the caller's cancellation capability. A later Cancel returns that authority to the fold, which privately projects the matching correlation.

Exact proxy rejection removes the entry after preserving StartFailed with the still-local definition as Present and all creation settlement. Exact proxy commit stores ProxyIncarnation and either:

  • waits with the complete prepared input when activation capacity is full; or
  • consumes the lowest waiting OperationCorrelation, forms the infallible ProxyOperationWitness/ProxyOperationId pair, emits the initial input, and enters AwaitingInputReceipt in the same transition.

Input settlement acceptance enters AwaitingOutcome. Rejection releases activation occupancy, marks the durable StartFailed definition Transferred, preserves the complete input in diagnostic settlement, drains the empty stable proxy, and never retries automatically.

An exact initial Ready outcome releases occupancy, enters Ready, stores the opaque worker evidence privately, and emits exactly one durable Started with the stable proxy. Any non-ready outcome emits StartFailed and retires/drains the proxy. A report before accepted input settlement is rejected; the interpreter must discharge source settlement before later child report admission.

After every occupancy release, waiting starts/replacements issue in increasing OperationCorrelation up to the positive limit.

Replace transitions

Replace is admissible only from Ready or Empty. Before acceptance, the supervisor constructs one complete transaction-local PreparedReplace, reserving its operation/cancel pair. A failure returns the complete replacement and leaves the base entry unchanged. Success moves the cancel authority into the acceptance action and every other field into Replacing::WaitingForAuthorization; no partial replacement phase is committed.

While waiting for authorization, cancellation returns the replacement and restores the exact base with a bounded Cancelled terminal record. Authorization forms the infallible proxy-operation pair and moves the replacement input to settlement.

Input rejection restores the base, emits one durable ReplacementFailed with definition Transferred, and preserves the complete input through diagnostic settlement. Input acceptance enters AwaitingOutcome.

StableProxy joins the ready predecessor's exact stop with successor work before publishing one replacement outcome; an empty proxy has no predecessor drain. DynamicSupervisor consumes that one completed outcome. A ready result enters Ready with fresh worker evidence and emits one Replaced after validating the nested replaces evidence against the retained base. A pre-birth failure enters Empty with the validated replaces evidence; a post-birth failure enters Empty with the successor attempt returned by StableProxy. Both emit ReplacementFailed. This is the same EmptyAfter projection owned by AA-01; the supervisor does not infer which worker the proxy now names. It never reports success or returns an already-transferred worker definition.

Cancellation after emission suppresses both outcomes, drains the exact proxy, and eventually emits OperationCancelled to the durable lifecycle owner. It cannot revive the predecessor or pretend the proxy stopped creating work.

Stop, unexpected exit, and unavailability

Stop accepts a ready, empty, or still-starting entry. Its immediate reply describes admission only. The durable lifecycle owner receives completion or runtime rejection.

Before StopAccepted, the fold fallibly reserves StopCorrelation. For a committed proxy, the exact shutdown correlation is then formed totally from the retained entry identity and proxy capability, and one shutdown is emitted. Settlement rejection preserves the request and reason. If the proxy is otherwise live, a stop-originating ready/empty entry is restored only when no authoritative exit has arrived; a failed StopFinished is durable realization, not an admission rejection. If exit and settlement arrive in the other order, the closed join preserves both and never resurrects the entry.

For a still-creating proxy, stop retains the creation result obligation. Exact creation rejection removes the entry. Exact commit emits one shutdown. Any locally owned initial definition transfers to the durable WorkerChangeInterrupted { interruption: ExplicitStop } outcome. An already-emitted input resolves first: rejection moves the complete returned input to diagnostic custody, while acceptance requires the exact late proxy result in the same lifecycle value. No Transferred label substitutes for an owned worker value.

An exact spontaneous worker stop from Ready first makes the entry unavailable and emits UnexpectedWorkerStopped. KeepEmpty enters Empty and continues to consume capacity. Retire enters Retiring, shuts down the stable proxy, and releases capacity only after exact drain. Neither policy restarts a worker.

Stable-proxy death in any phase retires that exact entry generation. It settles the active operation through typed host transfer, emits the corresponding lifecycle failure and diagnostic, and cannot affect another entry or later use of the same key.

Every exact Unavailable report is delivered once to the mandatory durable lifecycle route with key, generation, sender, phase, and command intact. It is valid during starting, ready, empty, replacing, stopping, cancelling, and draining. Foreign or stale source capability is a diagnostic, not a fold error that loses the command.

Cancellation and bounded token retention

Cancel first selects the semantic key and matches the checked, supervisor-global operation carried by its opaque authority. Operations never wrap or reuse, so entry generation is not a second cancellation coordinate; it remains the durable identity of the retained entry and its lifecycle messages.

  • A matching locally owned definition returns once.
  • A matching transferred definition returns CancellationReceipt::Pending and moves the entry into exact drain.
  • A matching active cancellation returns CancellationReceipt::Cancelled.
  • A matching most-recent committed record returns CancellationReceipt::Committed.
  • A matching most-recent cancelled record returns CancellationReceipt::Cancelled.
  • An older, removed-generation, foreign, or never-issued authority returns CancellationReceipt::Stale without mutation.
  • Global drain returns CancellationReceipt::Draining.

The model retains no unbounded operation history. When a new operation is accepted, the prior terminal record retires. This bounded policy must be documented in any public cancellation contract; indefinite Committed answers would require a growing tombstone set or an impermissible provenance inference from sequence arithmetic.

Entry retirement and key reuse

Capacity counts every retained entry, including cancelling and retiring ones. An entry is removed only after:

  1. pending proxy creation resolves;
  2. every emitted proxy input settles or transfers;
  3. every proxy-private activation outcome resolves or transfers;
  4. exact proxy shutdown/exit resolves or transfers;
  5. lifecycle, diagnostic, and rejected-delivery ownership has a host; and
  6. forced-retirement residual ownership, if any, moves to the surviving root.

Removal retains no key tombstone. A later Start for the same key reserves a fresh supervisor-global EntryGeneration, proxy creation ID, and operation. Because child routes and generations are never reused, a late fact from an old entry cannot match the new entry. It is returned complete as a stale diagnostic.

Allocator exhaustion rejects future starts with their workers intact. It does not justify reuse of an old generation or child route.

Global shutdown normalization

The first global shutdown atomically:

  1. closes start, replace, and stop admission;
  2. makes cancel report CancellationReceipt::Draining while query remains available;
  3. transfers every locally owned start/replacement definition to one durable WorkerChangeInterrupted { interruption: SupervisorShutdown { change } } outcome and retains already-emitted definitions through their exact input settlement or proxy outcome;
  4. preserves every emitted creation, proxy-input settlement, and atomic proxy outcome obligation;
  5. transforms every retained entry into one exhaustive drain entry;
  6. emits at most one shutdown for every committed live proxy;
  7. retains every pending proxy creation until exact commit/rejection; and
  8. reserves and emits one exact deadline request when selected.
DrainEntry =
    ResolvingProxyCreation { identity, creation: CreationId, local_values }
  | DrainingProxy {
        identity,
        proxy,
        outstanding: EntryOutstanding,
        shutdown: ProxyStopPhase,
    }
  | Drained { identity, result: Graceful | Absent | Forced { residual } }

EntryOutstanding =
    Idle
  | StartWaiting { operation, input }
  | StartEmitted { operation, witness: ProxyOperationWitness, settlement_or_outcome }
  | ReplaceWaiting { operation, base, input }
  | ReplaceEmitted { operation, base, witness: ProxyOperationWitness, settlement_or_outcome }
  | ExplicitStop { stop, settlement_or_exit }
  | Cancellation { operation, outstanding }
  | Retirement { cause, outstanding }

Repeated shutdown is idempotent. Late creation, proxy report, input settlement, shutdown settlement, and proxy exit can settle only their exact drain entry. They cannot restore mutation or emit Started/Replaced.

Exact proxy exit consumes every outstanding operation through the same typed child terminal/drain settlement required by AA-01 and AA-10. If the runtime cannot return emitted input ownership when normal proxy reports are suppressed during shutdown, that is a shared real-boundary blocker; the model does not replace it with flags, abort, logging, or dropped values.

Deadline drain

DeadlinePhase =
    WaitingWithoutDeadline
  | Scheduling { correlation, settlement }
  | Waiting { correlation }
  | Fired { correlation, observed_at }

WaitForActorGraph may wait indefinitely and owns no timer. RetireActorGraphAfter reserves one exact correlation. Reservation failure or schedule rejection immediately forces every unresolved entry into Drained(Forced { residual }) with that exact rejection as cause; it never degrades into unbounded waiting.

When the exact deadline fires, every unresolved entry transfers its complete phase, proxy or creation ID, operation, local values, and action settlements to the surviving lifecycle host. No accepted stop, ready worker, successful replacement, or normal exit is fabricated. The root remains live until residual external work settles.

The supervisor selects normal termination only when every entry is drained and every final action has a settlement owner.

Stale, overlap, and contradiction laws

  • A management key alone never matches a lifecycle fact.
  • A proxy creation or exit advances only its exact entry generation and creation ID or exact capability.
  • A proxy-input settlement advances only its exact generation, source, ProxyOperationWitness, operation kind, and dispatched phase.
  • An initial outcome cannot satisfy replacement, and replacement cannot satisfy initial.
  • Replacement outcome evidence must name the exact retained predecessor.
  • A duplicate report cannot release another activation slot.
  • A cancel authority cannot cancel another operation on the same key.
  • An old-generation fact cannot advance a reused key.
  • A stop correlation cannot consume a replacement or cancellation settlement.
  • A delivery rejection cannot roll back an already committed state transition.
  • Contradictory authoritative facts retain both sides and transfer to diagnostics.
  • Diagnostic rejection is terminal and never recursively diagnoses itself.

Every rejected fact preserves the semantic entry state and emits one complete RejectedLifecycleFact through the configured diagnostic disposition.

Feature-catalogue trace

Requirement familyModel evidence
DS-BUILDconstruction domain, mandatory durable lifecycle owner, independent diagnostics, no fixed policy
DS-STARTcomplete pre-commit preparation, fresh proxy, admission/realization split, stable capability publication
DS-QUERYtotal public projection with no Option/flags or private phase leakage
DS-STOPpending-birth stop, exact shutdown/exit join, durable completion
DS-REPLACEbase-preserving preparation, exact predecessor join, fresh ready outcome
DS-EXITcomplete unexpected-stop policy and durable unavailability
DS-RETENTIONbounded complete table, fresh global generation, no tombstones, exact stale diagnostics
DS-CANCELphase-exact definition ownership, logical post-transfer cancellation, bounded terminal token law
DS-SHUTDOWNmutation closure, exhaustive entry drain, pending creation, deadline residual transfer

Every row remains a model claim, not implementation status.

Independent-model obligations

The later executable oracle must use independent vocabulary and compare complete traces. At minimum it must cover:

  • zero/invalid construction limits and missing mandatory policies;
  • start at capacity, duplicate key, and every correlation reservation failure;
  • proxy creation commit/rejection/exit orderings;
  • activation limits one and two with operation-order issuance;
  • accepted/rejected proxy-input settlement before atomic outcome;
  • start cancellation in every phase, including late commit/readiness;
  • replace from ready and empty, including StableProxy's internal predecessor stop/outcome orders and the supervisor's single completed result;
  • replacement cancellation before and after definition transfer;
  • stop during pending start, ready, empty, replacement, and cancellation;
  • unexpected worker exit under both policies;
  • total query projection in every operating and draining phase;
  • operation-token replay, bounded terminal retention, and old-token staleness;
  • remove/reuse of one key with a fresh generation and late old facts;
  • foreign/duplicate/wrong-kind/wrong-source lifecycle facts;
  • request, lifecycle, diagnostic, and shutdown delivery rejection;
  • shutdown from every entry phase, pending creation, late ready, and repeated shutdown;
  • deadline reservation failure, schedule rejection, exact firing, and residual root settlement; and
  • complete named actions for every accepted/rejected transition.

Falsification findings and comparison obligations

AA-20 records these findings for governing-document reconciliation:

  1. The clean-room task text called durable lifecycle ownership optional, while the feature, solution, and DevX contracts make one durable route mandatory. This model follows the governing mandatory law.
  2. The solution/type inventory list a public Retire command, but the feature law already makes Stop release ready/empty entries and automatically removes fully retired entries. No distinct Retire transition remains; retaining both would violate the one-operation/one-spelling DevX target.
  3. The solution/query vocabulary stores and exposes Reserved, but successful preparation and proxy creation emission are one fold. Without a real intervening settlement, Reserved is transaction-local and not queryable.
  4. The cancellation contract did not bound how long terminal operation tokens remain recognizable. This model retains only the active or most recent terminal operation per entry; older tokens return CancellationReceipt::Stale.
  5. The stop requirements both restrict admission to available/empty and require stop during pending start to wait for creation. This model selects the latter explicit race law and accepts stop during Starting.
  6. The governing dynamic action product omits explicit route-delivered diagnostic, deadline, fact-rejection, and child-terminal settlement operations required by its own laws. Activation remains proxy-private; the supervisor authorizes it by emitting the opaque proxy input, not through a second activation lane.
  7. The current production template conflates key with child nonce, retains the start reply route as lifecycle owner, exposes Option<phase>, has no entry limit/generation/cancellation/deadline law, and reconstructs worker progress instead of consuming AA-01's atomic proxy outcome. It is comparison evidence, not an implementation candidate for this model.
  8. Governing dynamic syntax supplies worker per operation while construction selects activation, but it does not state where a possibly affine concrete activation plan is materialized or returned. This model treats worker as the complete WorkerSubmission once the static activation contract is applied. An executable design must infer and hide that composition without cloning, reconstructing, or asking users to spell the product.

These findings do not authorize production surface. The solution, feature catalogue, type inventory, coverage matrix, DevX contract, retained-core decision, and research audit must be reconciled before an executable task relies on a changed law.

This specification is ready to compare with the FIFO and keyed-pool models. It does not make AA-21 eligible: executable dynamic supervision still depends on AA-07's completed proxy and interpreter boundary audit.

FIFO-pool falsification model

Status and authority

This document is the AA-30 independent semantic model for one FIFO worker pool. It is a non-production falsification oracle. It does not select Rust types, define another behavior algebra, implement a pool, or mark a production coverage row implemented. docs/engineering/atomic-actor-solution.md remains the production design authority.

The actor-model laws used here are isolated processing of one communication, communications to known recipients, fresh actor creation, and explicit next behavior. The pool itself, direct worker ownership, FIFO admission, bounded backlog, circular worker selection, activation authorization, recovery, at-least-once retry, opaque completion authority, action settlement, and actor-graph drain are derived constructions or deliberate Bombay policies. Neither Agha's actor model nor message-arrival indeterminacy supplies FIFO pool semantics.

The model is deliberately not a supervisor containing a work queue. It reuses policy values where their meanings are identical, but it contains no stable proxy, supervisor member state, proxy operation, public worker capability, nested supervisor behavior, keyed affinity, or redispatched supervisor event.

Runtime route selection is owned normatively by docs/atomic-runtime-settlement.md. The pool issues and stores only a CreationId for each direct worker creation; it never chooses or stores a runtime route before emitting CreateChild. Any older reservation label below denotes that creator-visible correlation before interpretation and routed evidence only in the returned runtime settlement. It does not authorize a separate route request, waiting state, or public route.

AA-30 is exercised by the clean-room FifoPool aggregate and independent customer, recovery, retirement, and queue models. H04b proves typed assignment completion lowering and H02 implements total action settlement. H03 assigns terminal lifecycle custody to Bombay through the documented upstream contract; that Engine/root integration remains an upstream gate rather than a FIFO aggregate gap. Legacy WorkerPool tests remain historical characterization evidence, not an architecture or independent model.

The model must falsify designs that make any of these claims false:

  1. The roster is non-empty, ordered, and contains each semantic worker role once.
  2. Every installed or replacement worker is a freshly created actor. A role, route, attempt, or sequence value is not actor identity.
  3. The stable pool actor is the only public service capability. Exact worker capabilities remain pool-private.
  4. The pool directly owns worker creation, initialization, activation, readiness, recovery, and drain. No nested proxy or supervisor owns them.
  5. Every accepted job has exactly one authoritative customer obligation and is either queued, assigned, or being terminally settled—never two of them.
  6. Backlog capacity counts queued jobs only. Zero capacity permits immediate assignment and rejects waiting ownership.
  7. Every worker has at most one assignment. Only an exact ready incarnation is eligible.
  8. No queued job coexists with an eligible idle worker after a completed fold.
  9. Jobs leave the queue in admission order. Worker choice starts at one circular declaration-order cursor and advances after each assignment.
  10. A completion must match its opaque authority, assignment, creator-local child nonce, private worker-birth evidence, role, and active phase. It resolves one customer outcome.
  11. A matching worker stop resolves its active assignment once before recovery. Retry is at-least-once execution and preserves FIFO admission order.
  12. Assignment delivery, completion, and worker stop may arrive in any order. Their join cannot duplicate a retry, terminal customer outcome, or recovery decision.
  13. Irrecoverable topology loss cannot strand accepted queued or assigned work.
  14. Shutdown closes admission, returns every queued and assigned job once, disables dispatch/retry, and drains every owned or still-creating worker.
  15. Stale, duplicate, foreign, wrong-worker-birth, and contradictory facts preserve current ownership and have an explicit diagnostic disposition.
  16. Every accepted input produces one next state and one complete named action product. No effect is ambient.

“Atomic” means one local Behavior fold commits one pool state and its complete Actions. It does not claim atomic delivery, creation, execution, recovery, or customer observation across actors.

Model vocabulary

The following names describe the oracle. They are not proposed public Rust names.

Role = one semantic worker label, unique inside this pool
RoleOrder = immutable declaration order retained for the pool lifetime

WorkerBirthAttempt = fresh non-reused CreationId issued by the pool
RoutedWorkerBirth = interpreter-private { attempt: WorkerBirthAttempt, route }
WorkerBirthEvidence = opaque non-routable evidence for one committed birth
WorkerRecipient = pool-private exact routable capability for one committed worker
WorkerIncarnation = { recipient: WorkerRecipient, evidence: WorkerBirthEvidence }

BirthKind = Initial | Replacement { recovery: RecoveryTicket, replaces: WorkerBirthEvidence }
WorkerSubmission = complete owned worker definition and activation work

RequestCorrelation = caller-authored opaque submission correlation, echoed only
JobId = fresh non-reused customer-visible correlation issued by the pool
AdmissionOrdinal = fresh non-reused private total order for one accepted job
AssignmentId = fresh non-reused private correlation for one dispatch attempt
CompletionAuthority = opaque affine authority bound to AssignmentId and WorkerBirthEvidence
CompletionCorrelation = pool-retained non-authorizing half of that exact authority
CompletionEvidence = consumed CompletionAuthority paired with one result
DispatchCorrelation = {
    assignment: AssignmentId,
    retained: CompletionCorrelation,
    authority: CompletionAuthority,
}

RecoveryTicket = fresh non-reused correlation for one role recovery
RecoveryOrdinal = one-based admitted recovery count for that role
TimerCorrelation = { timer, generation }
ActivationTicket = fresh non-reused correlation occupying one authorization slot
ShutdownCorrelation = exact { role, WorkerIncarnation }

A child route, role, attempt, job, admission ordinal, assignment, recovery ticket, timer, or activation ticket is correlation, not actor identity. Only committed fresh creation yields WorkerIncarnation. Its recipient is routable only inside the pool's effects and lifecycle state; customers and worker messages never receive it as a service capability.

CompletionAuthority has no public constructor or inspectable fields. It is the affine authority half of one freshly issued pair; the pool retains the non-authorizing CompletionCorrelation half. The worker can only consume its half with the assignment to form assignment.complete(result). The resulting completion chooses no customer, pool address, role, parent path, send lane, or inspectable worker evidence. The current ChildReport boundary attaches only the creator-local child nonce, not an exact WorkerIncarnation. Exact completion matching therefore combines that nonce with the authority's opaque WorkerBirthEvidence; retained comparison evidence cannot manufacture a completion. A concrete lowering of that private evidence remains a blocker rather than an interpreter assumption.

Every correlation allocator has one complete result:

Reservation<T> = Reserved(T) | Rejected(Exhausted | Collision { candidate: T })

A rejection never wraps, overwrites, or reuses a correlation. The transition rules below say whether it rejects an unaccepted submission, returns an accepted job, retires a worker attempt, or begins actor-graph failure. Merely declaring a value fresh is not a total allocation law.

Construction domain

One complete definition contains:

FifoPoolDefinition = {
    initial_factory,
    roles: NonEmptyOrderedUnique<Role>,
    activation: ActivationContract,
    activation_limit: PositiveMaximum,
    recovery: RecoveryPolicy,
    backlog_capacity: NonNegativeMaximum,
    interruption: Fail | Retry,
    distribution: FIFO,
    actor_drain: ActorDrainPolicy,
    diagnostics: DeliverTo { route } | Terminate,
}

RecoveryPolicy contains eligibility, the typed worker source required by permanent or transient recovery, restart budget and inclusive window, immediate or checked delayed timing, and RetireRole | StopPool topology failure. Temporary recovery contains no worker source. Recovery is always one role at a time; a FIFO pool has no one-for-all or rest-for-one strategy.

ActorDrainPolicy is exactly:

WaitForActorGraph
RetireActorGraphAfter { deadline }

Construction fails for an empty roster, duplicate role, zero activation limit, invalid deadline, missing policy, or worker protocol that cannot accept the exact assignment product. FIFO construction has no selector or placeholder selector.

Before the pool exists, the initial factory is invoked for every role in declaration order and every worker reservation is fallibly prepared. If one factory or reservation fails, the construction error owns every already prepared definition and correlation; no partial fleet, budget charge, activation occupancy, or Actions commits. This is a Bombay all-or-none initial-preparation policy. Later creation and activation realization resolve independently for each committed role.

The worker sum may be heterogeneous only when every variant accepts one common concrete assignment protocol and produces one common concrete result type. Static closed sums are allowed; erasure and runtime registries are not.

AA-30 selects no builder spelling, typestate, public identifier representation, trait, wrapper, alias, or macro.

Pool state

FifoPoolState =
    Operating {
        definition,
        members: OrderedMemberMap,
        backlog: Fifo<QueuedJob>,
        cursor: RoleCursor,
        activation: ActivationCapacity,
        budget: RestartBudget,
        allocators,
    }
  | Draining {
        definition,
        members: OrderedDrainMap,
        deadline: DeadlinePhase,
        allocators,
    }
  | Stopped

The Rust aggregate also has Constructed, which owns the prepared worker roster before its one initialization transition, and ForcedRetirement, which owns unresolved retiring workers plus the exact shutdown-ID or deadline failure after a terminal transition. The sketch above describes the operating law; those two additional source states preserve initialization rejection and terminal custody. A real interpreter still has to prove transfer of the ForcedRetirement value to the parent or root custodian.

OrderedMemberMap has exactly one member for each declared role. Roles are never inserted, removed, or reordered. Retired remains as a terminal cell so cursor order and late-fact classification do not depend on sequence arithmetic.

The backlog owns jobs in original admission order. backlog_capacity is the new-admission waiting bound: a submission may queue only while the current backlog length is below it. An interrupted already-accepted assignment under Retry may re-enter even when that admission bound is full. Reinsertion is by its immutable AdmissionOrdinal, before every later-admitted queued job and after every earlier-admitted queued job; it is not unconditional front insertion. The absolute queue bound is therefore backlog_capacity + roles.len(), because each role can contribute at most its one formerly active assignment. There is no unbounded overflow and no second in-flight map: a live assignment is owned by its exact member.

RoleCursor denotes the first declaration-order position inspected for the next assignment. Selection wraps once, skips non-idle and retired roles, and chooses the first exact Idle. After assignment to role r, the cursor moves to the declaration-order successor of r; retirement never compacts or reorders the ring.

ActivationCapacity is derived from member states containing an occupied ActivationTicket. A declaration-order queue is derived from members waiting for authorization; correlated flags or a second occupancy counter are forbidden.

Customer ownership sums

CustomerObligation = {
    job: JobId,
    admitted_at: AdmissionOrdinal,
    customer: CustomerRoute,
    retained_payload,
}

QueuedJob = {
    obligation: CustomerObligation,
    assigned_role: None | Some(Role),
}

AssignedJob = {
    obligation: CustomerObligation,
    assignment: AssignmentId,
    completion: CompletionCorrelation,
    worker: WorkerIncarnation,
    role: Role,
}

AssignmentCommand = {
    execution_payload,
    completion: CompletionAuthority,
}

The queue owns QueuedJob. One busy member owns AssignedJob. The worker owns only the moved AssignmentCommand; it never owns the customer route or the canonical customer obligation.

Both Fail and Retry require a retained canonical payload while a cloned execution payload is sent to the worker. Clone preparation occurs before the candidate transition commits. If application cloning unwinds, no next state or Actions exists; the model does not promise to reconstruct a value already moved into a panicking fold.

The customer protocol is one closed sum:

AdmissionOutcome =
    Accepted { request: RequestCorrelation, job: JobId }
  | Rejected { request: RequestCorrelation, payload, reason: AdmissionRejection }

TerminalCustomerOutcome =
    Completed { job: JobId, role: Role, result }
  | ReturnedQueued { job: JobId, payload, reason: QueuedReturnReason }
  | ReturnedAssigned { job: JobId, role: Role, payload, reason: AssignedReturnReason }

RequestCorrelation is supplied by the caller and echoed unchanged in both admission outcomes. The pool neither allocates it nor trusts it as internal job identity; customers using one route can still distinguish concurrent requests. Admission commit moves it into the emitted Accepted; it is not retained in the accepted job. Rejection moves it into Rejected. If either delivery rejects, the lifecycle host owns that complete outcome. Accepted and Rejected are admission outcomes. The other three are the only terminal outcomes. A rejected submission was never accepted. A terminal outcome removes its obligation from actor state when the delivery attempt is emitted; rejected outcome delivery transfers that exact complete value to the lifecycle host and never reconstructs an active job.

Complete member sum

Member =
    Creating {
        role,
        reservation: WorkerReservation,
        kind: BirthKind,
        prior_stop: NoStop | StoppedBeforeBirth { stop },
    }

  | Initializing {
        role,
        worker: WorkerIncarnation,
        kind: BirthKind,
        init_attempt: InitAttempt,
    }

  | WaitingForActivationAuthorization {
        role,
        worker: WorkerIncarnation,
        kind: BirthKind,
        activation_permit,
        activation_plan,
    }

  | ActivationDispatched {
        role,
        worker: WorkerIncarnation,
        kind: BirthKind,
        ticket: ActivationTicket,
        begin_attempt: ActivationAttempt,
    }

  | Activating {
        role,
        worker: WorkerIncarnation,
        kind: BirthKind,
        ticket: ActivationTicket,
        activation_attempt,
    }

  | DrainingPreReady {
        role,
        worker: WorkerIncarnation,
        outstanding: PreReadyOutstanding,
        cause: PreReadyDrainCause,
        after_drain: Recover { stop } | Retire { reason },
    }

  | Idle {
        role,
        worker: WorkerIncarnation,
    }

  | Busy {
        role,
        worker: WorkerIncarnation,
        job: AssignedJob,
        join: AssignmentJoin,
    }

  | Recovering {
        role,
        predecessor: WorkerIncarnation,
        stop,
        recovery: RecoveryPhase,
    }

  | Stopping {
        role,
        worker: WorkerIncarnation,
        outstanding: StopOutstanding,
        after_stop: Retire { reason } | StopPool { reason },
    }

  | Retired {
        role,
        reason,
    }

AssignmentJoin is the exhaustive delivery/completion/stop join:

AssignmentJoin =
    AwaitingDeliveryAndTerminal { delivery: AssignmentDeliveryAttempt }
  | DeliveryAcceptedAwaitingTerminal
  | CompletionBeforeDelivery {
        delivery: AssignmentDeliveryAttempt,
        completion: CompletionEvidence,
        later_stop: NoStop | Stopped { stop },
    }
  | StopBeforeDelivery {
        delivery: AssignmentDeliveryAttempt,
        stop,
        later_completion: NoCompletion | Completed { completion: CompletionEvidence },
    }

The delivery effect and lifecycle host own the moved AssignmentCommand while settlement is unresolved; actor state retains only AssignmentDeliveryAttempt and the non-authorizing completion half. CompletionBeforeDelivery owns the returned completion input, while StopBeforeDelivery owns the authoritative stop. They are disjoint, so no queue entry duplicates the stop. A completion after StopBeforeDelivery is retained for stale or contradictory settlement; a stop after CompletionBeforeDelivery is retained in later_stop for one recovery after completion settles. Shutdown transfers any unresolved join intact.

The lifecycle host—not Initializing—owns the linear initialization settlement and activation plan while initialization is unresolved. Actor state retains only InitAttempt. An exact InitResult later transfers either the activation permit and plan, the rejected settlement and plan, or the stopped plan back once. ActivationDispatched likewise retains correlation while the host owns the moved begin request. These are the same ownership laws as AA-01, applied directly rather than by reusing proxy state.

PreReadyOutstanding, StopOutstanding, and every recovery variant own complete exact values rather than booleans. A definition or activation plan is either local, moved into an action settlement, or transferred to the lifecycle host—never reconstructed.

Recovery phase

RecoveryPhase =
    Scheduling {
        recovery: RecoveryTicket,
        timer: TimerCorrelation,
        prepared: PreparedReplacement,
        schedule_attempt: RestartScheduleAttempt,
    }
  | WaitingForTimer {
        recovery: RecoveryTicket,
        timer: TimerCorrelation,
        prepared: PreparedReplacement,
    }
  | ReadyToCreate {
        recovery: RecoveryTicket,
        prepared: PreparedReplacement,
    }

PreparedReplacement owns a fresh worker definition, fresh WorkerReservation, checked delay evidence, and one budget charge. Emitting the creation moves the member to Creating; no recovery phase and creating phase own the definition simultaneously.

Recovery eligibility is total:

PolicyNormal stopAbnormal stop
Permanenteligibleeligible
Transientretire roleeligible
Temporaryretire roleretire role

One matching stop can admit at most one recovery. Preparation invokes the factory, reserves the recovery and worker-birth correlations, prunes budget at the interpreter-authored monotonic stop time using an inclusive window, validates the charge, and computes checked timing before commit. Any failure commits no recovery, timer, creation, or budget charge; it applies the selected topology-failure reaction to the already stopped role.

Immediate timing enters ReadyToCreate. Delayed timing enters Scheduling. Exact schedule acceptance enters WaitingForTimer; exact rejection applies topology failure and returns the complete prepared replacement to lifecycle settlement. An exact timer moves to ReadyToCreate and emits creation in that same fold. Stale or duplicate schedule/timer facts cannot create another worker.

Complete input sum

FifoPoolInput =
    Submit { request: RequestCorrelation, payload, customer: CustomerRoute }
  | Shutdown

  | WorkerBirthResolved(WorkerBirthResolution)
  | InitializationSettled(InitializationSettlement)
  | ActivationBeginSettled(ActivationBeginSettlement)
  | WorkerReady(WorkerReadyFact)
  | WorkerStopped(WorkerStopFact)

  | AssignmentSettled(AssignmentSettlement)
  | WorkerCompleted { child: ChildRouteNonce, completion: CompletionEvidence }

  | RestartScheduleSettled(RestartScheduleSettlement)
  | RestartTimerElapsed(RestartTimerFact)
  | WorkerShutdownSettled(WorkerShutdownSettlement)

  | DrainDeadlineSettled(DeadlineScheduleSettlement)
  | DrainDeadlineElapsed(DeadlineFact)

Every fact carries exact role, reservation or incarnation, operation kind, and correlation required by its transition. A payload match without exact source and phase is never sufficient.

WorkerBirthResolution is:

Committed {
    role,
    reservation: WorkerReservation,
    worker: WorkerIncarnation,
    init_attempt: InitAttempt,
}
Rejected {
    role,
    reservation: WorkerReservation,
    returned_submission: WorkerSubmission,
    reason,
}

Successful installation is authoritative before worker initialization effects are interpreted. Initialization settlement and later activation are separate facts; commit cannot be rolled back because one later effect rejects.

InitializationSettlement is one host-authored result:

ReadyForActivation {
    role, worker, init_attempt,
    permit: ActivationPermit,
    plan: ActivationPlan,
}
Rejected {
    role, worker, init_attempt,
    rejected_settlement,
    plan: ActivationPlan,
    reason,
}
Stopped {
    role, worker, init_attempt,
    stop,
    plan: ActivationPlan,
}

The actor never stores the unresolved settlement or plan. Only this exact result moves the lawful next values into actor state or drain ownership.

AssignmentSettlement is attached to the creator-local child nonce:

Accepted { child: ChildRouteNonce, assignment }
Rejected {
    child: ChildRouteNonce,
    assignment,
    returned: AssignmentCommand,
    reason,
}

Rejection proves only that this delivery was not accepted. It is not fabricated worker termination. Before the pool resolves the job, AuthorityReunion consumes the returned command's affine authority together with the exact retained CompletionCorrelation:

AuthorityReunion =
    Cancelled { assignment, worker_birth: WorkerBirthEvidence }
  | Mismatch { retained, returned_authority }

Cancelled proves that neither half remains live. Mismatch transfers both complete values to terminal settlement and cannot requeue, complete, or reuse the assignment. After successful reunion the pool safely requeues the proven- unaccepted job, quarantines and drains the exact worker, and applies recovery only after exact terminal or forced transfer.

Required semantic action product

The pool fold's minimum model product is:

FifoPoolActions = {
    worker_creations: [CreateWorker { reservation, submission }],
    worker_creation_observations: [ObserveWorkerCreation { reservation }],
    worker_stop_observations: [ObserveWorkerStop { child: ChildRouteNonce }],
    activation_begins: [BeginWorkerActivation { child, attempt, permit, plan }],
    activation_cancellations: [CancelWorkerActivation { child, attempt }],
    worker_assignments: [DeliverAssignment { child, assignment, command }],
    worker_shutdowns: [ShutdownWorker { child, correlation }],
    restart_schedules: [ScheduleRestart { recovery, timer, deadline }],
    deadline_schedules: [ScheduleDrainDeadline { timer, deadline }],
    admission_deliveries: [DeliverAdmission { route, outcome }],
    terminal_customer_deliveries: [DeliverCustomerTerminal { route, outcome }],
    diagnostic_deliveries: [DeliverDiagnostic { route, diagnostic }],
    terminal_diagnostic_transfers: [TransferTerminalDiagnostic { diagnostic }],
    rejected_fact_transfers: [TransferRejectedFact { fact, reason }],
    forced_drain_transfers: [TransferDrainResidual { residual, cause }],
}

WorkerCompletionActions = {
    parent_completion_reports: [ReportCompletionToParent {
        authority: CompletionEvidence,
    }],
}

The heterogeneous product has one closed owned-operation view for ordered application and rejection ownership:

OwnedOperation =
    CreateWorker { reservation, submission }
  | ObserveWorkerCreation { reservation }
  | ObserveWorkerStop { child: ChildRouteNonce }
  | BeginWorkerActivation { child, attempt, permit, plan }
  | CancelWorkerActivation { child, attempt }
  | DeliverAssignment { child, assignment, command }
  | ShutdownWorker { child, correlation }
  | ScheduleRestart { recovery, timer, deadline }
  | ScheduleDrainDeadline { timer, deadline }
  | DeliverAdmission { route, outcome }
  | DeliverCustomerTerminal { route, outcome }
  | DeliverDiagnostic { route, diagnostic }
  | TransferTerminalDiagnostic { diagnostic }
  | TransferRejectedFact { fact, reason }
  | TransferDrainResidual { residual, cause }
  | ReportCompletionToParent { authority: CompletionEvidence }

AppliedOperation =
    WorkerCreationSubmitted { reservation }
  | WorkerCreationObservationStarted { reservation }
  | WorkerStopObservationStarted { child }
  | WorkerActivationBeginDelivered { child, attempt }
  | WorkerActivationCancelDelivered { child, attempt }
  | AssignmentDelivered { child, assignment }
  | WorkerShutdownDelivered { child, correlation }
  | RestartScheduleSubmitted { recovery, timer }
  | DrainDeadlineScheduleSubmitted { timer }
  | AdmissionDelivered { request }
  | CustomerTerminalDelivered { job }
  | DiagnosticDelivered { diagnostic_correlation }
  | TerminalDiagnosticTransferred { diagnostic }
  | RejectedFactTransferred { fact, reason }
  | DrainResidualTransferred { residual, cause }
  | ParentCompletionReported { child, completion_correlation }

AppliedOperation records exactly which owned operation crossed the runtime boundary without pretending that creation, observation, scheduling, worker execution, or customer receipt has already completed. Their later domain facts remain distinct inputs. Each applied variant carries the correlation needed to match that later fact; where the draft vocabulary does not yet define a diagnostic correlation, that missing allocator is part of the lowering blocker, not permission to use a generic label.

Because the locked Environment::apply is ordered but non-transactional, one action application reports a closed prefix result:

ActionBatchSettlement =
    Complete { applied: [AppliedOperation] }
  | Partial {
        applied_prefix: [AppliedOperation],
        rejected: { operation: OwnedOperation, reason },
        not_attempted_suffix: [OwnedOperation],
    }

OwnedOperation is the exact flattened sum of FifoPoolActions and WorkerCompletionActions; it is not an erased envelope. Partial owns the rejected operation and returns every unattempted payload to the lifecycle host in authored order. A rejected ReportCompletionToParent therefore returns the complete CompletionEvidence through rejected.operation; no separate generic parent-rejection label is needed. The current runtime supplies neither this complete prefix result nor the rejected parent operation: local parent reporting discards a closed-parent send rejection. Both are explicit AA-30 blockers.

These are named semantic operations. No positional .inner traversal, proxy lane, supervisor report, runtime registry, callback, channel, untyped envelope, or ambient effect occurs inside the fold. A production representation may reuse existing concrete lower-order products only after proving that it preserves every lane, source, ordering, and rejection owner.

Initialization creation is interpreted before dependent observations. For one fold, admission outcomes precede assignments, terminal customer outcomes precede successor assignments, and diagnostics precede a terminal verdict. These interpretation orders are explicit Bombay policies, not general actor- model ordering guarantees.

Ownership table

ValueActor-side ownerOwner after emissionTerminal law
Unaccepted submissionincoming Submitrejected-admission settlementreturned complete; never enters queue/member state
Queued customer obligationFIFO backlogterminal-customer settlement when removedassigned once or returned once
Assigned customer obligationexact Busy memberterminal-customer settlement on result/interruption/shutdownremoved before another terminal outcome can emit
Execution payload and completion authoritytransition-local candidateassignment-delivery settlement, then exact workerrejection returns both; state retains only canonical obligation/correlation
Unsettled assignment joinexact Busy member with one customer obligationexact assignment/completion/stop settlement, or lifecycle host on forced drainone exhaustive variant selects one terminal job disposition
Initialization plan/settlementlifecycle host while unresolved; actor retains InitAttempt onlyexact InitializationSettlement transfers the lawful next valuesnever duplicated in Initializing
Worker definitionconstruction/recovery candidatecreation settlementrejection returns exact definition; commit establishes fresh worker
Exact worker capabilityone membereffects borrow delivery authority; lifecycle host owns forced residualexact stop or forced transfer retires it
Activation slotactivation member phaseactivation settlement after emissionready, rejection, stop, or forced transfer releases once
Recovery candidatelocal preparation then Recoveringtimer/creation settlementrejection returns complete prepared ownership
Customer outcometransition-localroute delivery settlementrejection transfers outward; never recreates job
Diagnostictransition-localdiagnostic route or terminal settlementrejection is terminal and non-recursive
Drain residualexact drain membersurviving lifecycle hostnever fabricated as successful stop/completion

Transition notation

  • AD: submission admission and immediate assignment/queue/rejection.
  • WB: worker birth resolution.
  • IN: initialization settlement.
  • AZ: activation authorization release.
  • AS: activation-begin settlement.
  • WR: exact readiness.
  • WS: exact worker stop.
  • DS: assignment delivery settlement.
  • CP: exact completion.
  • RS / RT: restart schedule settlement / timer fact.
  • S0: first shutdown normalization.
  • S=: repeated shutdown, no duplicate effects.
  • WD: worker drain settlement or exit.
  • DDS / DF: drain-deadline schedule settlement / exact deadline.
  • F-: preserve semantic ownership and emit one complete rejected-fact diagnostic through the configured disposition.
  • NA: Stopped accepts no actor input; late settlements belong to the surviving lifecycle host.

All cells below assume exact creator-local nonce, private worker-birth evidence, role, kind, correlation, and phase. Any mismatch is F-.

Total pool-mode matrix

ModeSubmitShutdownWorker lifecycleAssignment settlement/completionRecovery timerDrain timer
OperatingADS0WB/IN/AS/WR/WS/WDDS/CPRS/RTF-
Drainingreject unchangedS=WB/IN/AS/WR/WS/WDDS/CPRS/RTDDS/DF
StoppedNANANANANANA

Submission during drain emits Rejected { request, payload, ShuttingDown }; the customer route and payload never enter pool ownership.

Total operating-member matrix

MemberBirthInitActivation settlementReadyStopAssignment settlementCompletionRestart timer
CreatingWBF-F-F-joinF-F-F-
InitializingF-INF-F-WSF-F-F-
waiting authorizationF-F-F-F-WSF-F-F-
ActivationDispatchedF-F-ASF-WSF-F-F-
ActivatingF-F-F-WRWSF-F-F-
DrainingPreReadyF-settlesettlesettle staleWDF-F-settle only
IdleF-F-F-F-WSF-F-F-
Busy::AwaitingDeliveryAndTerminalF-F-F-F-joinjoinjoinF-
Busy::CompletionBeforeDeliveryF-F-F-F-joinjoinF-F-
Busy::StopBeforeDeliveryF-F-F-F-F-joinstale CPF-
Busy::DeliveryAcceptedAwaitingTerminalF-F-F-F-WSF-CPF-
RecoveringWB only after emissionF-F-F-F-F-stale CPRS/RT
StoppingF-settlesettlesettle staleWDsettlestale CPsettle only
RetiredF-F-F-F-F-F-stale CPF-

Creating may observe an exact stop before its birth observation because child report and creation-observation paths have no global arrival order. It stores that one stop. Later commit joins the exact incarnation and resolves it without advertising readiness; later creation rejection plus prior authoritative stop is a contradiction retaining both facts.

Initialization and activation

Initialization emits every preflighted worker creation in declaration order. Each member enters Creating before the action is exposed. Creation rejection retires or stops the pool according to topology failure and never reports a successful birth.

Creation commit enters Initializing { init_attempt }; the lifecycle host retains the unresolved initialization settlement and activation plan. Exact ReadyForActivation transfers its permit and plan into WaitingForActivationAuthorization. Rejected or Stopped transfers its complete plan into DrainingPreReady; neither rolls back the committed worker or begins recovery while an installed actor remains owned.

After every transition that releases activation capacity, AZ scans waiting roles in declaration order. Reserving an ActivationTicket, changing the member to ActivationDispatched, and emitting BeginActivation are one fold. Ticket exhaustion/collision enters DrainingPreReady with complete activation ownership; it cannot leave a silent installed worker waiting forever.

The model accepts begin settlement in either order with worker stop and forced drain; no synchronous interpreter guarantee is assumed. Acceptance enters Activating. Rejection enters DrainingPreReady and returns the complete activation request through exact settlement. Exact Ready releases its ticket and invokes the same fill_fifo transition used after completion and retry. If backlog is non-empty, the member becomes Busy directly; it never transiently commits Idle.

Stop or forced transfer in any occupied activation phase releases exactly one ticket. Late readiness after stop is stale and never restores eligibility.

Admission

Submit { request, payload, customer } evaluates one transaction:

  1. reject ShuttingDown or NoRecoverableWorkers before allocation;
  2. inspect worker availability and queue occupancy; when no Idle member exists and the new-admission bound is full, reject BacklogFull before allocation;
  3. reserve one fresh accepted-job pair { JobId, AdmissionOrdinal }; pair exhaustion/collision rejects with JobCorrelationUnavailable and retires every candidate;
  4. if an Idle member exists, reserve one fresh DispatchCorrelation; rejection emits DispatchCorrelationUnavailable and does not fall back to queue admission;
  5. prepare the retained execution clone and exact assignment action; unwind produces no transition;
  6. commit Busy, advance the cursor, emit Accepted { request, job }, then emit the assignment; or
  7. when step 2 proved queue capacity, append the obligation with NeverAssigned in AdmissionOrdinal order and emit Accepted { request, job }.

These branches are disjoint. Full/unserviceable rejection performs no internal allocation; job-pair rejection and immediate-dispatch rejection return the original request, route, and payload; no preparation failure silently queues a job or leaves it accepted without an owner. Every candidate from an uncommitted attempt is retired and never reused.

The Accepted delivery attempt does not gate assignment or queue ownership. Its rejection transfers the complete admission outcome to the lifecycle host; it cannot roll the job back or become its terminal outcome.

FIFO fill and correlation failure

fill_fifo is a pure finite transition applied after readiness, completion, retry insertion, assignment return, or member retirement:

  1. maintain the queue sorted by immutable AdmissionOrdinal; a newly retried job is inserted after all smaller ordinals and before all larger ordinals;
  2. while both the queue and an exact Idle member exist, inspect the smallest ordinal and the first idle role at or after the cursor;
  3. prepare its execution clone and reserve a fresh assignment/completion pair;
  4. on success, remove that head, commit the member to Busy, advance the cursor, and append one assignment action;
  5. on correlation exhaustion/collision, remove that head and emit exactly one terminal outcome selected by its origin—ReturnedQueued for NeverAssigned, or ReturnedAssigned for Retried—then continue; and
  6. on no idle member or empty queue, stop.

Returning a job on correlation failure is necessary because leaving it at the head beside an idle worker would violate the maintained invariant and could wait forever after permanent exhaustion. A clone unwind produces no fold and therefore does not run step 5.

After every committed operating transition:

backlog.is_empty() OR no member is Idle

Assignment settlement and completion

Delivery settlement, completion report, and worker stop have no assumed cross-path order. AssignmentJoin consumes them as follows:

  • AwaitingDeliveryAndTerminal + Accepted becomes DeliveryAcceptedAwaitingTerminal.
  • AwaitingDeliveryAndTerminal + completion becomes CompletionBeforeDelivery; no customer outcome is emitted yet.
  • AwaitingDeliveryAndTerminal + stop becomes StopBeforeDelivery; no interruption outcome or recovery is admitted until delivery settles.
  • CompletionBeforeDelivery + stop retains that stop in later_stop.
  • StopBeforeDelivery + completion retains the completion in later_completion; stop remains the winning terminal ordering.
  • CompletionBeforeDelivery + Accepted resolves Completed, then evaluates its retained later stop once when present.
  • StopBeforeDelivery + Accepted applies Fail | Retry once, diagnoses any retained later completion as stale, then evaluates recovery once.
  • Any exact Rejected settlement first attempts affine AuthorityReunion. With no retained completion it safely reinserts the proven-unaccepted job by AdmissionOrdinal with its prior assigned role, quarantines the worker, and evaluates any retained stop once. If a completion is already retained, the claimed returned authority contradicts its prior consumption; the fold emits ReturnedAssigned { ContradictoryAssignmentSettlement }, transfers both facts terminally, and begins whole-pool drain.

No branch relies on synchronous settlement. The customer obligation remains in the exact Busy join until one settlement branch selects its disposition. Wrong assignment, child nonce, worker-birth evidence, or phase is F-.

A completion matches the current assignment only when its creator-local child nonce, opaque WorkerBirthEvidence, assignment correlation, and retained non-authorizing half all agree. It never relies on the interpreter attaching an exact incarnation capability. A matching completion after accepted delivery:

  1. removes the active correlation;
  2. consumes the canonical obligation;
  3. emits Completed once;
  4. makes the exact member available;
  5. runs fill_fifo in the same fold; and
  6. commits Idle only if no queued job can be dispatched.

A duplicate, cross-worker, old-birth, unknown-authority, or wrong-phase completion preserves all current state and emits the complete result as a stale operational diagnostic. It never selects a customer route from a tombstone.

Interruption and recovery

An exact stop of Idle makes the role unavailable and evaluates recovery. An exact stop after accepted delivery removes the active completion correlation:

  • Fail emits ReturnedAssigned { WorkerStopped } once;
  • Retry retains the canonical obligation and reinserts it by immutable AdmissionOrdinal with its prior assigned role; the next dispatch reserves fresh authority only when an exact idle worker is available; and
  • dispatch-correlation rejection for that retried head emits ReturnedAssigned { RetryPreparationRejected } once.

Ordered reinsertion handles multiple interrupted workers: if A was admitted before B, stopping A then B still produces [A, B], not [B, A]. Retry is not a new admission: it may exceed the new-admission backlog limit, but the complete queue remains bounded by backlog_capacity + roles.len(). fill_fifo may assign the job to a different exact idle role in the same fold. Because the prior worker may have executed before stopping, this is explicitly at-least-once execution.

The queue retains only the immutable ordinal and whether the obligation was previously assigned to one role. Worker exit and rejected delivery have identical future ordering, dispatch, shutdown, and customer-outcome semantics, so retaining which event caused reinsertion would store history rather than current queue truth. The authoritative stop remains solely in AssignmentJoin until recovery consumes it, then in Recovering; it is never copied into the queued job. Duplicate stop during recovery is F-.

After assignment resolution, recovery eligibility and preparation run from the exact stop. Eligible recovery emits the same typed non-empty worker-source request used by fixed supervision, selecting this one role. Bombay interprets that request outside Behavior and returns its complete generic settlement; the pool owns what the returned submission or rejection means. Worker-source failure, budget denial, clock regression, checked delay overflow, recovery/birth correlation rejection, creation rejection, or schedule rejection applies RetireRole | StopPool. RetireRole runs fill_fifo across surviving members. If no live or recoverable member remains, every queued job receives ReturnedQueued { NoRecoverableWorkers } in FIFO order. StopPool enters the ordinary shutdown normalization rather than dropping jobs through a terminal error.

Shutdown normalization

The first Shutdown atomically:

  1. closes admission;
  2. removes every queued obligation in FIFO order and emits one ReturnedQueued { PoolShutdown } for each;
  3. removes every assigned correlation and emits one ReturnedAssigned { PoolShutdown } for each;
  4. disables retry, recovery admission, readiness publication, and successor dispatch;
  5. cancels un-emitted prepared replacement and restart-timer ownership;
  6. transforms every member into one exhaustive drain member;
  7. emits at most one exact shutdown request per committed worker;
  8. retains every pending worker creation until commit or rejection; and
  9. for deadline policy, reserves and emits one exact drain timer.

The drain sum is:

DrainMember =
    ResolvingCreation {
        role,
        worker,
        activation,
        creation_kind,
        stop: None | Some,
    }
  | Worker {
        role,
        actor,
        work: Created { activation }
            | Initializing
            | WaitingForActivation
            | ActivationDispatched
            | Activating
            | Idle,
        shutdown: NotRequested | Waiting { request, stop },
    }
  | AwaitingWorkerPreparation { role, request }
  | AwaitingRestartSchedule { role, request }
  | Drained { role }

The worker work sum owns actor-side correlations for unresolved initialization, activation, assignment, and shutdown operations; the lifecycle host owns their moved requests and linear values. Customer ownership has already moved to terminal customer outcomes; a late completion is stale diagnostic data and cannot be retained as another job.

Creation rejection enters Drained. An exact creation accepted during drain starts no initialization or activation work. Without a prior stop it emits one shutdown and enters Worker { work: Created { activation }, ... }; the activation value stays local until exact stop transfers it to diagnostic custody. With a prior exact stop, the worker is already retired and the activation transfers immediately. A foreign or reversed result changes no member. Shutdown rejection remains in the existing request/stop reunion while exact stop observation is still possible; rejection alone never completes the drain.

An exact worker stop consumes every matching outstanding child-side settlement, preserves complete unresolved values with the lifecycle host, and enters Drained(Graceful). Repeated shutdown is S=. Late restart, readiness, assignment, and completion facts settle or diagnose their exact cancelled ownership and can never reopen admission or dispatch.

Deadline drain

DeadlinePhase =
    WaitingWithoutDeadline
  | Scheduling { timer: TimerCorrelation, attempt: DeadlineScheduleAttempt }
  | Waiting { timer: TimerCorrelation }
  | Fired { timer: TimerCorrelation, observed_at }

WaitForActorGraph may wait indefinitely. RetireActorGraphAfter uses exact interpreter-authored monotonic time. Deadline correlation reservation failure cannot silently weaken it to unbounded waiting: the rejecting shutdown fold immediately transfers every unresolved member as forced-retirement custody.

Exact schedule acceptance enters Waiting. Exact schedule rejection also forces every unresolved member in that same fold. The residual preserves the complete timer request, rejection reason, worker or birth ownership, and every outstanding action settlement. Exact deadline firing performs the same forced transfer with the deadline fact as cause.

Forced transfer does not fabricate worker stop, assignment acceptance, completion, successful creation, recovery, or customer delivery. The stable root remains alive in lifecycle-host settlement until every transferred external obligation is resolved.

The pool selects normal actor termination only when every member is Drained and every action in the final turn has an exact settlement owner. Unrelated application children never enter this drain.

Stale, overlap, and contradiction laws

  • A role alone never identifies a worker fact.
  • Birth resolution advances only its exact role, reservation, attempt, and expected birth kind.
  • Initialization, activation, and readiness advance only their exact installed incarnation and expected phase.
  • Assignment settlement advances only its exact child nonce, private birth evidence, assignment, and AssignmentJoin variant.
  • Completion advances only the exact active accepted assignment and consumed opaque authority.
  • A completion carrying old worker-birth evidence cannot release a new worker birth's job.
  • Stop is consumed once by the exact member or drain state. It cannot admit a second recovery or interruption.
  • A recovery schedule or timer advances only its exact recovery and timer generation.
  • A delivery rejection cannot roll back already committed job, budget, cursor, or worker state; its complete payload moves to settlement.
  • Customer-outcome rejection cannot recreate a queue entry or assignment.
  • Contradictory authoritative facts preserve both facts for diagnostic or residual settlement.
  • Diagnostic rejection is terminal and non-recursive.

Every rejected fact preserves current semantic ownership and emits one complete RejectedPoolFact through the selected diagnostic disposition.

Feature-catalogue trace

Requirement familyModel evidence
FP-BUILDcomplete construction product, non-empty unique roles, static assignment/result protocol, explicit diagnostics/activation/drain
FP-TOPOLOGYdirect fresh workers, exhaustive pre-ready and recovery sums, activation capacity, no proxy/supervisor state
FP-ADMITcomplete customer submission, bounded queue, zero-capacity rule, typed reservation failure, accepted/rejected split
FP-ASSIGNprivate affine authority, one busy assignment, exact circular cursor, maintained no-idle-with-backlog invariant
FP-COMPLETEnonce plus private birth evidence, affine reunion, order-independent settlement/completion/stop join, one terminal result
FP-INTERRUPTfail/retry sum, admission-ordinal reinsertion, at-least-once law, no duplicated stop fact
FP-FAILUREone-role retirement, surviving dispatch, complete stranded-work return, separate diagnostics
FP-RETENTIONaccepted-job customer obligations plus assignment-only completion correlation and bounded action-settlement joins, no permanent tombstones
FP-SHUTDOWNadmission closure, exact queued/assigned extraction, pending creation, direct worker drain, forced residual transfer

Every row remains a model claim, not implementation status.

Independent-model obligations

The later executable model must use independent vocabulary such as worker cells, one queue, one accepted-job ledger, and one cursor. It must not copy these production-oriented phase names or the eventual implementation branches.

At minimum it must cover:

  • empty/duplicate construction, missing policy, zero activation limit, and factory/reservation failure at every role with no partial fleet;
  • worker birth commit/rejection and stop-before-birth in both orders;
  • initialization and activation acceptance/rejection, limits one and two, and declaration-order authorization;
  • readiness with empty and non-empty backlog and no intermediate idle state;
  • capacity zero, exact capacity, backlog full, shutdown admission, and no recoverable worker;
  • job, assignment, completion, recovery, activation, birth, and timer exhaustion/collision transitions;
  • cursor wrap, retired-role skipping, multiple idle workers, and FIFO batches;
  • completion followed by successor dispatch in one complete action;
  • duplicate, cross-worker, old-worker-birth, wrong-token, and unknown-token completion with result preservation;
  • assignment settlement before stop, stop before settlement, and replay of each side;
  • completion-before-stop and stop-before-completion under Fail and Retry;
  • ordered reinsertion for two or more interrupted workers and immediate reassignment to another idle worker;
  • permanent/transient/temporary recovery for normal and abnormal stop, budget boundaries, checked timing, schedule rejection, and restart exhaustion;
  • role retirement with surviving capacity and complete stranded-job return;
  • admission, customer outcome, assignment, diagnostic, creation, activation, timer, and shutdown delivery rejection;
  • shutdown from every member phase, every queued/assigned cardinality, pending birth, pending assignment join, repeated shutdown, and late completion;
  • deadline reservation failure, schedule rejection, exact firing, and forced lifecycle-host residual transfer; and
  • complete named actions for every accepted and rejected transition.

Properties after every generated step must include:

accepted_jobs = queued_jobs + assigned_jobs + terminally_settling_jobs
queued_jobs <= backlog_capacity + worker_roles
new submission queues only when queued_jobs < backlog_capacity
queued admission ordinals are strictly increasing
each worker has at most one assigned job
each job has at most one terminal customer outcome
backlog.is_empty() OR no worker is Idle
cursor is one position in the immutable declaration-order ring
active completion correlations are unique
retired correlations are never reissued

Falsification findings and comparison obligations

AA-30 records these findings for governing-document reconciliation:

  1. Unconditional retry-front insertion reverses two interrupted jobs when stop order differs from admission order. The corrected queue stores immutable AdmissionOrdinal and reinserts by that order.
  2. The initial draft stored linear initialization settlement and activation plan in actor state. The corrected model follows AA-01: the lifecycle host owns them while actor state retains only InitAttempt.
  3. The initial draft rejected completion before assignment settlement while accepting stop in that order, despite no locked causal guarantee. The corrected AssignmentJoin exhausts settlement, completion, and stop order.
  4. ChildReport attaches only a creator-local nonce. The corrected completion law combines that nonce with opaque authority-carried WorkerBirthEvidence; it does not claim an interpreter-attached exact incarnation.
  5. The initial retry queue copied the authoritative stop fact. Corrected queue provenance owns only admission ordinal, prior role, and semantic interruption class; the join/recovery path owns the stop once.
  6. Rejected assignment delivery returns the affine authority. Corrected AuthorityReunion consumes returned authority and retained non-authorizing evidence exactly once before safe reinsertion.
  7. The initial admission outcomes could not correlate concurrent requests on one customer route. Both corrected variants echo caller RequestCorrelation, distinct from pool-issued JobId.
  8. The initial admission algorithm allocated before full-backlog rejection and allowed queue fallback to overlap preparation failure. Corrected branches classify first, allocate only for an admissible candidate, and give every preparation failure one typed rejection.
  9. Generic settlement labels hid payload ownership and the locked runtime's non-transactional apply/closed-parent-report loss. The corrected model names every operation, exact settlement, applied prefix, rejected operation, and owned unattempted suffix. Concrete lowering remains blocked.
  10. Recovery reuses fixed-supervisor policy values but not state; its selected topology failure is RetireRole | StopPool. Backlog capacity bounds new admission while retry preserves the finite absolute capacity + roles queue bound.
  11. The current production pool contains stable proxies and a nested fleet ownership fold, exposes assignment/job identifiers to workers, and lacks the selected activation/opaque-authority/deadline laws. It is comparison evidence, not an implementation candidate. Its 550 green tests do not validate this oracle, and the current independent FIFO property model has one worker, so it cannot expose the two-worker retry-order counterexample.

These are falsification findings, not production API amendments. Before an executable task relies on any selected mechanism, the feature catalogue, solution, inventory, retained-core decision, research audit, and interpreter boundary must be reconciled together or the existing concrete boundary must be proved to express the same law unchanged.

First-slice non-features and blocker

AA-30 intentionally provides no:

  • Rust pool, worker, job, assignment, completion, recovery, builder, protocol, event, effect, or error type;
  • executable fold, model test, property, fuzz target, or benchmark;
  • proxy, supervisor, keyed-affinity, shared recovery engine, or nested pool;
  • interpreter for creation, activation, assignment, customer delivery, diagnostics, deadlines, or residual root ownership;
  • wrapper-composition, initialization-order, compiler/DevX, or migration proof; or
  • change to the locked kernel, actors, macros, testkit, runtime, examples, or public API.

The semantic document is complete enough for bounded comparison, but AA-30 is [!], not complete as an executable aggregate prerequisite. H04b proves that assignment.complete(result) lowers one unforgeable private parent completion without exposing a path or customer capability. H02 owns exact report and prefix/suffix action settlement. H03 records the required Bombay custody path; that upstream runtime work is not implemented in this repository. A clean-room FIFO model must still execute the independent-model obligations above before production can cite AA-30 as executable evidence. AA-40 may compare this law, but neither aggregate may extract shared production machinery before the same suite passes both real consumers.

Keyed-pool falsification model

Status and authority

This document is the AA-40 independent semantic model for one keyed worker pool. It is a non-production falsification oracle. It does not select Rust types, define another behavior algebra, implement a pool, or mark a production coverage row implemented. For the clean-room campaign this document owns the keyed aggregate law; lower-authority solution and synthesis documents must be corrected when they disagree. Rust representation remains separately unselected.

The semantic state, input, action, admission, assignment, retirement, and drain sums are complete in this revision. The independent bounded oracles in src/keyed_model.rs and its keyed/recovery.rs child pass in debug and optimized builds. They separately explore 22,621 binding/assignment prefixes and 22,621 recovery/shutdown prefixes. The first rejects deliberate generation reuse, stale mutation, accepted-work retargeting, cross-role queue consumption, and duplicate terminal outcomes. The second rejects candidate loss and worker restart after shutdown while checking one exact worker source, restart schedule, timer, and worker-shutdown owner after every prefix. AA-30 now supplies the first real assignment-authority consumer, and docs/atomic-runtime-settlement.md owns the retained total interpretation and terminal-custody contracts. This oracle does not duplicate either implementation.

The actor-model laws used here are isolated processing of one communication, communications to known recipients, fresh actor creation, and explicit next behavior. Direct worker ownership, key selection, affinity, bounded per-role backlogs, bounded binding retention, generation-safe reuse, opaque completion authority, recovery, action settlement, and actor-graph drain are derived constructions or deliberate Bombay policies. The actor model does not supply keyed-pool semantics.

The keyed pool is one independent aggregate transition. It is not a FIFO-pool wrapper, supervisor, stable proxy, nested behavior, or specialization that stores or forwards another template's state. It may compare AA-30's recorded value laws, but it owns distinct member, partition, binding, management, and transition sums. It may reuse only the separately proven direct-worker and assignment laws; it never depends on FIFO aggregate state.

Runtime route selection is owned normatively by docs/atomic-runtime-settlement.md. The pool issues and stores only a CreationId for each direct worker creation; it never chooses or stores a runtime route before emitting CreateChild. Any older reservation label below denotes that creator-visible correlation before interpretation and routed evidence only in the returned runtime settlement. It does not authorize a separate route request, waiting state, or public route.

The clean-room crates/actors keyed pool is subordinate implementation evidence against this model, never authority for it. It owns direct workers, bounded generation-safe bindings, Unbind, typed management outcomes, and per-role backlogs. Any implementation that instead nests a WorkerPool, routes through stable-proxy nonces, retains unbounded generationless bindings, omits typed management, or admits work to a stopping role is the obsolete architecture falsified by this model; it is not a parallel keyed-pool design.

The model must falsify designs that make any of these claims false:

  1. The worker roster is non-empty, ordered, and contains each semantic role once.
  2. Every installed or replacement worker is freshly created. Role, key, binding generation, route, and correlation are not actor identity.
  3. One submitted key is separate from its owned payload and is evaluated by one concrete selector only when no binding is retained.
  4. A binding proposed by admission commits if and only if the same transition accepts the submitted customer obligation. An explicit management rebalance may instead bind an absent key without submitting work.
  5. Binding capacity and per-role backlog capacity are distinct bounds. Zero backlog capacity lawfully permits immediate assignment only.
  6. Every accepted job permanently retains its admitted role. Rebalance, unbind, retry, and worker replacement cannot retarget it.
  7. Work for one role never consumes another role's backlog capacity or idle worker.
  8. Every live member phase projects to exactly one of AssignableNow, BacklogAdmissible, or Unavailable, without a wildcard or inferred readiness.
  9. No serviceable queued job for a role coexists with that role in eligible idle state after a completed transition.
  10. Each role has at most one active assignment. Completion matches opaque authority, exact worker-birth evidence, retained role, and active phase.
  11. Rebalance and unbind change future admission only. Every accepted queued or assigned job retains its original role and single customer obligation. Every management mutation is guarded by an exact absence or generation expectation.
  12. Reusing an unbound key receives a fresh opaque binding generation. Late management inputs for an absent or different generation cannot mutate it.
  13. The transition that makes a role permanently unusable returns that role's queued and assigned work once, removes every retained binding to the role atomically, releases binding capacity, and diagnoses each removed key and generation. Temporary recovery retains bindings.
  14. Shutdown closes admission, returns every accepted job from every role once, removes all bindings, and drains every owned or still-creating worker.
  15. Stale, duplicate, foreign, wrong-role, wrong-generation, wrong-worker- birth, and contradictory inputs preserve current ownership and have an explicit diagnostic disposition.
  16. Every accepted input produces one next state and one complete named action product. No effect is ambient.

“Atomic” means one local Behavior transition commits one keyed-pool state and its complete Actions. It does not claim atomic delivery, creation, worker execution, external activation, or customer observation across actors.

Model vocabulary

The following names are oracle vocabulary, not proposed public Rust names.

Role = one semantic worker label, unique inside this pool
RoleOrder = immutable declaration order retained for the pool lifetime

Key = caller-supplied semantic affinity key
BindingGeneration = fresh opaque non-reused correlation
Binding = { key: Key, generation: BindingGeneration, role: Role }
AdmittedBindingEvidence = opaque copyable { generation: BindingGeneration, role: Role }

WorkerBirthAttempt = fresh non-reused CreationId issued by the pool
RoutedWorkerBirth = interpreter-private { attempt: WorkerBirthAttempt, route }
WorkerBirthEvidence = opaque non-routable evidence for one committed birth
WorkerRecipient = pool-private routable capability for one committed worker
CurrentWorker = { recipient: WorkerRecipient, evidence: WorkerBirthEvidence }

RequestCorrelation = caller-authored opaque submission correlation, echoed only
JobId = fresh non-reused customer-visible correlation issued by the pool
AdmissionOrdinal = fresh non-reused private total order for one accepted job
AssignmentId = fresh non-reused private correlation for one dispatch attempt
CompletionAuthority = opaque affine authority bound to assignment and worker birth
CompletionCorrelation = pool-retained non-authorizing half of that authority

ManagementRequest = fresh caller-visible correlation
BindingExpectation = Absent | Exact(BindingGeneration)
RebalanceCommand = {
    request: ManagementRequest,
    key: Key,
    expected: BindingExpectation,
    target: Role,
    reply: ManagementRoute,
}
UnbindCommand = {
    request: ManagementRequest,
    key: Key,
    expected: BindingExpectation,
    reply: ManagementRoute,
}
ManagementCommand = Rebalance(RebalanceCommand) | Unbind(UnbindCommand)
RecoveryTicket = fresh non-reused correlation for one role recovery
ActivationTicket = fresh non-reused authorization occupancy correlation

BindingGeneration, like every other correlation above, is not an actor identity. It is allocated freshly for a newly committed binding rather than derived from a per-key counter. Removing a binding therefore leaves no permanent key tombstone. A later use of the same key obtains a fresh generation from the fallible allocator.

Binding is the sole pool owner of its retained Key. A job accepted through that binding receives only AdmittedBindingEvidence; it does not clone, own, or keep the key. Multiple jobs may copy the non-authorizing evidence without creating a binding, changing affinity, or extending binding retention. A rejected admission or management command returns its one complete owned key.

The selector is one concrete statically known function Fn(&Key) -> Role. It cannot select an address, nonce, worker birth, customer route, assignment lane, or behavior implementation. Its output is validated against the immutable semantic roster. It is evaluated at most once for one unbound submission and is not evaluated for an already-bound key.

Every correlation allocator is total:

Reservation<T> = Reserved(T) | Rejected(Exhausted | Collision { candidate: T })

Rejection never wraps, overwrites, reuses, or guesses a correlation. A later transition table must name the complete owner returned by every allocation failure before this model can be complete.

Construction domain

KeyedPoolDefinition = {
    initial_factory,
    roles: NonEmptyOrderedUnique<Role>,
    selector: one concrete Fn(&Key) -> Role,
    activation: ActivationContract,
    activation_limit: PositiveMaximum,
    recovery: RecoveryPolicy,
    backlog_capacity_per_role: NonNegativeMaximum,
    binding_capacity: PositiveMaximum,
    interruption: Fail | Retry,
    actor_drain: ActorDrainPolicy,
    diagnostics: DeliverTo { route } | Terminate,
}

ActorDrainPolicy =
    WaitForActorGraph
  | RetireActorGraphAfter { deadline }

Construction fails for an empty or duplicate roster, zero activation limit, zero binding capacity, invalid drain deadline, missing selector or policy, or a worker protocol that cannot accept the exact assignment product. Backlog capacity is non-negative because zero is immediate-assignment-only. There is no global backlog capacity and no FIFO placeholder selector.

The worker sum may be heterogeneous only when every variant accepts one common concrete assignment protocol and produces one common concrete result type. Static closed sums are allowed; erasure, a runtime registry, and downcasting are not.

AA-40 selects no builder spelling, typestate, public identifier representation, trait, wrapper, alias, or macro.

Top-level ownership state

KeyedPoolState =
    Operating {
        definition,
        roles: OrderedRoleTable,
        bindings: BoundedBindingMap,
        activation: ActivationCapacity,
        budget: RestartBudget,
        allocators,
    }
  | Draining {
        definition,
        roles: OrderedDrainRoleTable,
        bindings: DrainingBindingMap,
        deadline: DeadlinePhase,
        allocators,
    }
  | Stopped

The Rust aggregate also has Constructed, which owns the prepared worker roster before initialization, and ForcedRetirement, which owns unresolved retiring workers plus the exact shutdown-ID or deadline failure after a terminal transition. The sketch above describes the operating law; those two additional source states preserve initialization rejection and terminal custody. A real interpreter still has to prove transfer of the ForcedRetirement value to the parent or root custodian.

OrderedRoleTable has exactly one RoleCell for each declared role. One cell owns both that role's member phase and its FIFO queue; there is no separately mutable member map and partition map whose phases can disagree. Roles are never inserted, removed, compacted, or reordered. Retired membership remains a terminal role cell so late inputs and binding removal never depend on index arithmetic. Irrecoverable is a transition cause, not a second retained terminal phase.

BoundedBindingMap owns at most binding_capacity entries. It contains only currently retained bindings. Absence is not stored. Unbind and the transition committing permanent role unavailability delete entries and release capacity immediately. Queued and assigned work does not keep a binding entry alive; it owns admitted-binding evidence and its admission record independently.

Each role partition owns one FIFO queue with its own full backlog_capacity_per_role. A job admitted to role R can inhabit only R's queue or active assignment state. It cannot consume the queue budget of role S, even when S is idle. Retry reinserts within the same role by immutable admission ordinal rather than unconditional front insertion.

Accepted-work ownership

CustomerObligation = {
    job: JobId,
    admitted_at: AdmissionOrdinal,
    admitted_binding: AdmittedBindingEvidence,
    customer: CustomerRoute,
    retained_payload,
}

QueuedJob = {
    obligation: CustomerObligation,
    origin: NeverAssigned | Retried { interruption },
}

AssignedJob = {
    obligation: CustomerObligation,
    assignment: AssignmentId,
    completion: CompletionCorrelation,
    worker: CurrentWorker,
}

One accepted job has one authoritative CustomerObligation. It is owned by exactly one per-role queue, exact member assignment, or terminal settlement. The admitted-binding evidence is historical correlation data; it neither owns the key nor preserves or recreates a removed binding. The caller's RequestCorrelation is moved into the emitted Accepted admission outcome and is not retained in actor state. Retry may retain a canonical payload while an execution value has escaped to a worker, but that represents one semantic obligation and explicitly at-least-once execution, not exactly-once external side effects.

Total admission target eligibility

Admission never asks whether a role is merely “alive” or “eventually ready.” It exhaustively projects the exact member phase:

AdmissionTargetEligibility =
    AssignableNow { current_worker }
  | BacklogAdmissible
  | Unavailable { reason }

AssignableNow = ReadyIdle

BacklogAdmissible =
    Prepared
  | Creating
  | Initializing
  | WaitingForActivationAuthorization
  | ActivationDispatched
  | Activating
  | ReadyBusy
  | RecoveryAdmitted
  | DrainingPreReady { after_drain: ResumeRecovery }

Unavailable =
    Stopping
  | Retired
  | DrainingPreReady { after_drain: Retire }
  | ShutdownOwned

The projection is a total match over the eventual complete keyed-member sum. DrainingPreReady is classified from its stored exhaustive disposition, not from a cause, timer, or inferred future. A new or existing binding can accept to BacklogAdmissible only when that role's queue has capacity.

For an unbound submission, selection, role validation, binding-generation reservation, job/ordinal reservation, capacity checks, and either immediate assignment preparation or queue insertion preparation all succeed before one binding and one customer obligation commit together. Any rejection returns the complete submission and retains neither proposed binding nor job. The detailed failure and transition sums are enumerated below.

Generation-safe management

Management target eligibility is a separate total projection because a rebalance admits no job and therefore asks neither immediate assignability nor queue capacity:

ManagementTargetEligibility =
    Bindable
  | Unavailable { reason }

Bindable =
    Prepared
  | Creating
  | Initializing
  | WaitingForActivationAuthorization
  | ActivationDispatched
  | Activating
  | ReadyIdle
  | ReadyBusy
  | RecoveryAdmitted
  | DrainingPreReady { after_drain: ResumeRecovery }

Unavailable =
    Stopping
  | Retired
  | DrainingPreReady { after_drain: Retire }
  | ShutdownOwned

An unknown role is UnknownTarget, not an eligibility member. An irrecoverable input synchronously chooses and commits a permanently unavailable member transition; it is never retained as a parallel member phase. Temporary RecoveryAdmitted and DrainingPreReady { ResumeRecovery } remain bindable and retain existing bindings. Entering terminal pre-ready drain, Stopping, Retired, or global shutdown ownership atomically extracts every binding for that role. Thus no permanently unusable role retains future-admission affinity.

The management protocol is exhaustive:

ManagementOutcome =
    BoundAbsent {
        request,
        current: AdmittedBindingEvidence,
    }
  | Rebalanced {
        request,
        prior: AdmittedBindingEvidence,
        current: AdmittedBindingEvidence,
    }
  | RebalanceUnchanged {
        request,
        current: AdmittedBindingEvidence,
    }
  | Unbound {
        request,
        removed: Binding,
    }
  | AlreadyUnbound {
        command: UnbindCommand,
    }
  | Rejected {
        command: ManagementCommand,
        reason:
            StaleExpectation { actual: Absent | Exact(BindingGeneration) }
          | UnknownTarget
          | TargetUnavailable
          | BindingCapacityExhausted
          | GenerationReservationRejected
          | ShuttingDown,
    }

Successful management outcomes need not echo a key: absent rebalance moves the command's key into Binding; successful existing rebalance retains the table's existing key; successful unbind returns the removed Binding and its key. Every rejected outcome returns the complete command unchanged.

ManagementRoute follows the same explicit capability-clone custody law as the customer route. The transition prepares one target clone before committing a rejected outcome so the original route can remain inside the returned command. A successful outcome consumes the command route as its delivery target and does not retain it. Rejected outcome delivery returns the target clone and the complete command, including the original route. This duplicates routable capability data only; request, key, expectation, and generation evidence remain single semantic values.

For a key absent from BoundedBindingMap:

InputResult
Rebalance { expected: Absent, target } and target is Bindable, capacity remains, generation reservation succeedsMove the command key into Binding { fresh generation, target }; emit BoundAbsent.
Rebalance { expected: Absent, .. } but target is unknown/unavailable, capacity is full, or generation reservation rejectsPreserve absence; return the complete command in the exact typed rejection.
Rebalance { expected: Exact(_), .. }Preserve absence; return the complete command as StaleExpectation { actual: Absent }.
Unbind { expected: Absent, .. }Preserve absence; return AlreadyUnbound with the complete command.
Unbind { expected: Exact(_), .. }Preserve absence; return the complete command as StaleExpectation { actual: Absent }.

For a key bound at exact generation g to role r:

InputResult
Either command with expected: Absent or Exact other than gPreserve the binding; return the complete command as StaleExpectation { actual: Exact(g) }.
Rebalance { expected: Exact(g), target: r } and r is still BindableExplicit accepted no-op: preserve generation g, consume no capacity or allocator value, and emit RebalanceUnchanged.
Rebalance { expected: Exact(g), target } for another Bindable role and fresh generation g2 is reservedMove the stored key into Binding { generation: g2, role: target }; emit Rebalanced { prior: {g, r}, current: {g2, target} }. No second table entry exists.
Exact rebalance to an unknown or unavailable target, or fresh-generation reservation rejectionPreserve the complete old binding; return the complete command in the exact rejection.
Unbind { expected: Exact(g) }Remove and return the complete Binding, release capacity immediately, and emit Unbound.

Expectation comparison precedes target validation. No stale command can observe a later binding and then mutate it. Role-changing rebalance prepares the fresh generation before replacing the old binding, so allocation failure cannot leave an absent entry. Same-role rebalance deliberately preserves the generation: a management request that changes no affinity does not invalidate otherwise exact later inputs.

Complete role and worker sum

RoleCell = {
    role,
    member: KeyedMember,
    backlog: Fifo<QueuedJob>,
}

KeyedMember =
    Prepared { submission, reservation, kind }
  | Creating { reservation, kind, prior_stop }
  | Initializing { worker, kind, init_attempt }
  | WaitingForActivationAuthorization { worker, kind, permit, plan }
  | ActivationDispatched { worker, kind, ticket, begin_attempt }
  | Activating { worker, kind, ticket, activation_attempt }
  | DrainingPreReady { worker, outstanding, cause, after_drain }
  | Idle { worker }
  | Busy { worker, assigned: AssignedJob, join: AssignmentJoin }
  | Recovering { predecessor, stop, phase: RecoveryPhase }
  | Stopping { worker, outstanding, after_stop }
  | Retired { reason }

BirthKind = Initial | Replacement { recovery, replaces: WorkerBirthEvidence }
AfterPreReadyDrain = ResumeRecovery { stop } | Retire { reason }
AfterWorkerStop = Retire { reason } | StopPool { reason }

Each RoleCell owns at most one active assignment and one queue. Only Idle is assignable. A worker becoming ready first inspects its own role queue and commits directly to Busy when work exists; it commits Idle only when that queue is empty.

The direct-worker creation, initialization, activation, and exact-stop law is identical to AA-30: fresh creation commits before initialization settlement; the lifecycle host owns affine initialization and activation work while the actor retains exact correlations; readiness requires committed birth, successful initialization, accepted activation, and exact readiness proof; post-commit failure drains before recovery or retirement. This document uses that shared value law but does not embed FIFO aggregate state, cursor, or global queue behavior.

Activation occupancy is derived from ActivationDispatched and Activating. Waiting roles are released in immutable roster order. Reserving a ticket, moving permit and plan to the activation action, and storing the dispatched phase are one transition. Ticket failure drains the installed worker with the complete activation ownership; it never strands a silent worker.

Recovery sum

RecoveryPhase =
    Scheduling { recovery, timer, prepared, schedule_attempt }
  | WaitingForTimer { recovery, timer, prepared }
  | ReadyToCreate { recovery, prepared }

PreparedReplacement = {
    submission,
    reservation: WorkerReservation,
    checked_release,
    charge,
}

Recovery is one role at a time. It shares the complete Permanent | Transient | Temporary eligibility, inclusive monotonic restart limit, checked immediate or delayed release, and exact timer-correlation law with AA-30. It owns no fixed strategy and selects RetireRole | StopPool on topology failure. Permanent and transient recovery retain a typed worker source; temporary recovery retains no source. Eligible recovery selects one role through the same non-empty worker-source request as AA-30. Bombay executes the request outside Behavior; the keyed pool alone interprets the returned submission or rejection.

Temporary recovery preserves every binding to the role. A terminal recovery decision enters permanent role unavailability below. Factory, budget, clock, release, timer, reservation, creation, initialization, or activation failure cannot silently shrink ownership or fabricate a ready worker.

Admission protocol and outcomes

KeyedPoolInput =
    Submit { request, key, payload, customer }
  | Rebalance(RebalanceCommand)
  | Unbind(UnbindCommand)
  | Shutdown
  | WorkerBirthResolved(WorkerBirthResolution)
  | InitializationSettled(InitializationSettlement)
  | ActivationBeginSettled(ActivationBeginSettlement)
  | WorkerReady(WorkerReady)
  | WorkerStopped(WorkerStopped)
  | AssignmentSettled(AssignmentSettlement)
  | WorkerCompleted { child: ChildRouteNonce, completion: CompletionEvidence }
  | RestartScheduleSettled(RestartScheduleSettlement)
  | RestartTimerElapsed(RestartElapsed)
  | WorkerShutdownSettled(WorkerShutdownSettlement)
  | DrainDeadlineSettled(DeadlineScheduleSettlement)
  | DrainDeadlineElapsed(DrainDeadlineElapsed)

AdmissionOutcome =
    Accepted { request, job, binding: AdmittedBindingEvidence }
  | Rejected { request, key, payload, customer, reason }

AdmissionRejection =
    ShuttingDown
  | BindingCapacityReached
  | UnknownSelectedRole
  | RoleUnavailable
  | RoleBacklogFull
  | NoRecoverableWorkers
  | BindingGenerationUnavailable
  | JobCorrelationUnavailable
  | AssignmentCorrelationUnavailable

The customer route follows one explicit clone law. Before commit, the transition clones it once: the clone targets the admission outcome, while the original moves to the accepted CustomerObligation or the rejected outcome. Rejected delivery therefore returns a complete delivery containing the targeting clone and the original route. Payload, key, customer obligation, and completion authority are never cloned by this rule.

Admission is one transaction:

  1. reject global shutdown or absence of every serviceable or recoverable role;
  2. borrow the submitted key to search the binding table;
  3. for an existing binding, bypass the selector and use its exact role and generation;
  4. for an absent binding, invoke the selector exactly once, validate the role, check binding capacity, and reserve a fresh generation;
  5. project the exact role phase to AssignableNow, BacklogAdmissible, or Unavailable and check only that role's queue capacity;
  6. reserve fresh job and admission-ordinal correlations;
  7. for immediate assignment, reserve the assignment/completion pair and prepare execution and customer-route clones; preparation failure does not fall back to queuing;
  8. commit a proposed binding if and only if the same transition commits the customer obligation; and
  9. emit acceptance followed by assignment, append to that role's queue, or return the complete unchanged submission through one rejection.

No Key: Clone law follows from this transition. An absent accepted key moves into Binding; an existing binding already owns its key and the submitted equal key is consumed by the accepted command. Rejection returns the submitted key. A concrete map representation may impose only the comparison or borrowing law actually needed; compiler convenience cannot strengthen it to cloning.

Zero per-role backlog capacity permits immediate assignment and rejects waiting ownership. A retry may temporarily make one role's queue length capacity + 1, because that role has at most one interrupted assignment. It is inserted by immutable AdmissionOrdinal, never at the unconditional front.

After every operating transition, independently for each role:

role.backlog.is_empty() OR role.member is not Idle

No fill operation can consume another role's queue or worker.

Assignment and completion law

The complete AssignmentJoin and affine AuthorityReunion law is identical to AA-30 and is applied inside one RoleCell:

AssignmentJoin =
    AwaitingDeliveryAndTerminal { delivery }
  | DeliveryAcceptedAwaitingTerminal
  | CompletionBeforeDelivery { delivery, completion, later_stop }
  | StopBeforeDelivery { delivery, stop, later_completion }

Delivery acceptance, rejection, completion, and exact worker stop are accepted in every runtime-permitted order. Completion matches only the child nonce, opaque worker-birth evidence, assignment, retained non-authorizing half, admitted role, exact worker birth, and active phase. Binding-table contents are not part of completion matching and cannot retarget accepted work.

Matching completion emits one Completed outcome and fills only the admitted role's oldest queue entry. Matching exit after accepted delivery applies Fail | Retry once; retry retains the admitted role and reinserts by ordinal in that same role. Assignment rejection must reunite the returned affine authority with the retained half before the proven-unaccepted job can requeue. Mismatch or a completion that already consumed the authority transfers both inputs terminally and begins whole-pool drain. Duplicate, stale, foreign, old-birth, or wrong-role completion preserves current ownership and transfers the complete result through diagnostics.

Exactly one terminal customer outcome exists for each accepted job:

TerminalCustomerOutcome =
    Completed { job, role, result }
  | ReturnedQueued { job, role, payload, reason }
  | ReturnedAssigned { job, role, payload, reason }

QueuedReturnReason =
    PoolShutdown
  | RolePermanentlyUnavailable
  | NoRecoverableWorkers
  | DispatchCorrelationUnavailable

AssignedReturnReason =
    PoolShutdown
  | RolePermanentlyUnavailable
  | WorkerStopped
  | AssignmentReturnedUnaccepted
  | RetryPreparationRejected
  | ContradictoryAssignmentSettlement

Removal from the queue or member precedes emission. Rejected customer delivery transfers the complete outcome outward and never recreates work.

Permanent role unavailability

Temporary recovery retains role bindings. The transition selecting permanent unavailability atomically creates one RoleRetirement:

RoleRetirement = {
    role,
    queued: [QueuedJob],
    assignment: NoAssignment | AssignmentDrain { assigned, join },
    bindings: [Binding],
    worker: WorkerDrain,
    cause,
}

In that transition:

  1. admission and management projection for the role becomes unavailable;
  2. every queued obligation is extracted in admission order and moved to one ReturnedQueued outcome;
  3. an active assignment loses retry authority and moves with its complete join to terminal assignment settlement; it produces completion if completion had already lawfully won, otherwise exactly one ReturnedAssigned;
  4. every binding whose role matches is removed from the table, releasing capacity immediately;
  5. each complete removed Binding moves to one diagnostic containing its key, generation, role, and cause; and
  6. the exact worker and all outstanding effects enter drain.

The table is the only key owner. Jobs retain only generation and role evidence, so binding extraction never needs to clone a key and never invalidates customer ownership. A rejected diagnostic transfers its complete removed binding to the lifecycle host; it cannot restore the table entry.

No later rebalance, unbind, completion, recovery, or worker-ready input can revive the retired role. Another role remains independently serviceable.

Required semantic action product

KeyedPoolActions = {
    worker_creations,
    worker_creation_observations,
    worker_stop_observations,
    activation_begins,
    activation_cancellations,
    role_assignments,
    worker_shutdowns,
    restart_schedules,
    deadline_schedules,
    admission_deliveries,
    management_deliveries,
    terminal_customer_deliveries,
    diagnostic_deliveries,
    terminal_diagnostic_transfers,
    rejected_input_transfers,
    forced_drain_transfers,
}

WorkerCompletionActions = {
    parent_completion_reports,
}

Each field is a concrete named typed lane, not a generic pool envelope or a flattened FIFO aggregate product. Generic item interpretation and settlement are owned only by atomic-runtime-settlement.md: accepted items leave their receipt, rejected items return the complete request, blocked items retain the exact prerequisite, independent later items continue, and corruption retains the committed prefix plus exact remainder. Creation is the prerequisite only for operations using its uncommitted child binding.

Interpretation order is creation before its exact dependents; management and admission outcomes before assignments they announce; terminal customer outcomes before successor assignments; per-role assignments in roster order when one transition releases several roles; and diagnostics before a terminal verdict. These are Bombay policies, not actor-model guarantees.

Total mode and member matrices

ModeSubmitManagementShutdownWorker lifecycleAssignment/completionRecovery timerDrain timer
Operatingadmit/rejectexact management tablenormalize drainsettle exact rolesettle exact role joinsettle exact recoveryreject input
Drainingreject unchangedreject unchangedidempotentsettle drain onlysettle drain onlysettle cancelled worksettle exact deadline
Stoppednot admittednot admittednot admittedhost-owned late inputhost-owned late inputhost-owned late inputhost-owned late input
Member phaseBirthInitActivation settlementReadyStopAssignment settlementCompletionRestart timer
Prepared/Creatingexact birth joinrejectrejectrejectexact pre-birth joinrejectrejectreject
Initializingrejectaccept exactrejectrejectexact drainrejectrejectreject
waiting authorizationrejectrejectrejectrejectexact drainrejectrejectreject
ActivationDispatchedrejectrejectaccept exactrejectexact joinrejectrejectreject
Activatingrejectrejectrejectaccept exactexact joinrejectrejectreject
DrainingPreReadysettle onlysettle onlysettle onlystaledrainrejectrejectsettle only
Idlerejectrejectrejectrejectinterrupt/recoverrejectstalereject
busy delivery pendingrejectrejectrejectrejectjoinjoinjoinreject
busy completion-firstrejectrejectrejectrejectjoinjoinduplicatereject
busy stop-firstrejectrejectrejectrejectduplicatejoinretain stale/contradictoryreject
busy delivery acceptedrejectrejectrejectrejectinterrupt/recoverrejectcompletereject
Recoveringonly after exact creation emissionrejectrejectrejectrejectrejectstalesettle exact
Stopping/retirement drainsettle onlysettle onlysettle onlystaledrainsettle onlystalesettle only
Retiredrejectrejectrejectrejectrejectrejectrejectreject

Every cell means exact role, reservation or worker birth, generation where applicable, operation kind, assignment, worker-birth evidence, and phase. Mismatch preserves state and moves the complete input to one non-recursive diagnostic. Management expectations are evaluated by their separate exhaustive tables above and never by this lifecycle matrix.

Shutdown normalization and drain

The first Shutdown atomically:

  1. closes submission and management admission;
  2. extracts and removes every binding, moving each complete key, generation, and role value to terminal custody or a selected binding-removal diagnostic;
  3. extracts every per-role queue in role order and FIFO order and emits one ReturnedQueued { PoolShutdown } per obligation;
  4. removes the customer right from every active assignment and emits exactly one ReturnedAssigned { PoolShutdown }; any retained completion becomes stale diagnostic ownership and the remaining affine delivery join moves to drain;
  5. disables dispatch, retry, recovery admission, and readiness publication;
  6. retains pending creation, initialization, activation, assignment, timer, and shutdown settlement ownership in one exact drain role;
  7. emits at most one shutdown per committed direct worker; and
  8. reserves and emits one exact deadline request for deadline policy.
DrainRole =
    ResolvingBirth { role, reservation, local_values, prior_stop }
  | DrainingWorker { role, worker, outstanding, stop_phase }
  | Drained { role, result: Absent | Graceful | Forced { residual } }

DeadlinePhase =
    WaitingWithoutDeadline
  | Scheduling { timer, attempt }
  | Waiting { timer }
  | Fired { timer, observed_at }

Repeated shutdown emits nothing twice. Birth rejection is Absent; birth commit is drained; commit plus prior authoritative stop is a contradiction, not readiness. Shutdown rejection retains the request and reason while exact stop observation remains live.

Deadline reservation or scheduling rejection cannot weaken the configured bound into an infinite wait. It transfers every unresolved role, binding removal, assignment join, child operation, timer, and external authority to Forced { residual }. Exact deadline firing does the same. It fabricates no stop, readiness, completion, acceptance, or recovery. The pool selects normal termination only when every role is drained and every final action has an exact settlement owner.

Stale, overlap, and conservation laws

  • Key equality alone never matches a management input after generation changes.
  • A role alone never identifies a worker or assignment input.
  • Binding expectation comparison precedes target validation and mutation.
  • Birth, initialization, activation, stop, recovery, assignment, and completion inputs advance only exact retained correlations and phases.
  • Rebalance, unbind, recovery, replacement, and retry never retarget accepted work.
  • One role cannot consume another role's queue capacity or idle worker.
  • A removed binding generation is never reissued or inferred from arithmetic.
  • Customer, management, diagnostic, and rejected-input delivery rejection never rolls back committed state and returns the complete value.
  • Contradictory authoritative inputs retain both values in terminal custody.
  • Diagnostic rejection is terminal and never recursively diagnosed.

After every generated step:

accepted obligations = queued + assigned + terminally settling
retained bindings <= binding capacity
each retained key has exactly one fresh generation and one role
each accepted job has one immutable admitted role
each role has at most one assignment
each job has at most one terminal customer outcome
each role queue is ordinal-ordered and <= backlog capacity + 1
role queue is empty OR its member is not Idle
permanently unavailable roles retain no binding

Feature trace and executable evidence

Requirement familyModel evidence
KP-BUILDconstruction domain, concrete selector, direct-worker protocol, distinct positive binding and activation limits
KP-AFFINITYatomic absent binding plus job, exact eligibility, per-role capacity, immutable admitted role
KP-REBALANCEgeneration expectations, same-role unchanged, fresh role-changing generation, complete command recovery
KP-ENDcomplete direct-worker lifecycle, assignment join, permanent role extraction, shutdown and drain
KP-RETENTIONsole key-owning binding table, no tombstone, fresh generation, stale denial

The independent keyed_model uses bins, leases, work slips, and service cells rather than these specification names. Its focused tests cover two roles and keys, zero and one capacity limits, every member eligibility, absent and exact expectations, same-role and cross-role rebalance, unbind and reuse, stale generations, permanent retirement, assignment delivery/completion/stop permutations, retry ordering, shutdown, and forced residuals. A depth-four enumeration checks the complete invariant set after all 22,621 prefixes. Its keyed/recovery.rs child uses a workshop, ordered bays, one recruiter, and a candidate-ownership map. A separate depth-four enumeration checks 22,621 recovery/shutdown prefixes, including concurrent stops, declaration-order source release, preparation returned during shutdown, all restart-schedule dispositions, accepted-timer cancellation, and both worker receipt/exit orders.

The inversion tests corrupt each of the seven named laws independently. The audit rejects generation reuse as GenerationReused, stale mutation as StaleMutation, accepted-work movement as QueueLocation, cross-role assignment as AssignmentRole, and double settlement as DuplicateTerminal.

AA-30's feature-complete production slice now supplies the first real opaque completion and affine-authority consumer. Generic total interpretation and terminal custody remain owned by docs/atomic-runtime-settlement.md. AA-40 is the retained keyed semantic oracle; production lowering must reuse those contracts rather than reopen or duplicate them.

The retained production startup checkpoint uses one passive direct-worker transition owner for both AA-30 and AA-40 successful creation, initialization, activation start, and readiness. AA-40 alone locates the role, applies activation capacity, and drains that role's queue. A Primary job queued before readiness is not consumed when Replica becomes ready; the deliberate cross-role inversion fails at that exact assertion. Foreign worker identity, wrong creation kind, foreign initialization, foreign activation, and duplicate activation start all retain the selected role and move the complete input to diagnostics. Assignment reunion, recovery, permanent role extraction, and shutdown now have clean-room production witnesses. Catalogue-wide compatibility, Bombay runtime lowering, and the final fixed-point audits remain open; this document does not claim those wider gates.

The production recovery suite also crosses shutdown after the exact restart schedule has been accepted and before its timer arrives. A drop-tracked worker submission remains owned by the terminal cancellation diagnostic until that action is released; shutdown emits no replacement creation and stops immediately. Deliberately dropping the submission during the shutdown transition fails at the ownership assertion.

Engineering records

These documents preserve the design campaign behind Bombay Behavior: research classification, candidate type inventories, acceptance targets, verification evidence, downstream-impact analysis, and audit results. They remain published for traceability, but they are not an additional public API surface.

The canonical contracts, actor catalogue, normalized aggregate laws, current crate documentation, and production types govern whenever terminology or an intermediate proposal in these records differs from the retained design.

The repository quality audit and checklist records the 2026-09-28 review of all workspace crates, verified gaps, and completion criteria for further simplification and testing work.

The interpreter ownership and startup PRD uses the current working code as its baseline. It specifies complete assignment and proxy rejection return, generic retained acceptance, coherent creation and initialization custody, and downstream interpreter acceptance tests. It also defines staged implementation gates before broader consolidation.

Repository quality audit and completion checklist

Audit date: 2026-09-28. Baseline: 435560ce7bea8ad3330ee2d42e5034f837a80602. Scope: all five workspace crates, their test and benchmark targets, the nested macro fixture and fuzz workspaces, public documentation, and verification gates.

The repository has a substantial typed algebra and meaningful adversarial tests. It also has gaps between its documented contracts, current composition surface, and what the tests prove. Address those gaps before expanding the catalogue. The best initial reductions are redundant test interfaces and dependencies, repeated effect-product machinery, and stale documentation. Aggregate state must be reduced only after proving that the removed distinction is unnecessary.

This is an audit and work list, not a claim that every branch is verified. All crates were inventoried; manual review covered public entry points, effect and creation interpretation, every actor family, representative transitions and test oracles, macros, and tooling. Source scans supplement that review. No line or branch coverage measurement, complete mutation campaign, or downstream Bombay Engine integration run was performed for this audit. Production code and existing tests were not changed at the audited baseline. Repairs made on the working branch are recorded below.

Inventory and interpretation of the evidence

Counts below are physical Rust lines, including comments and inline tests. They measure review surface, not essential complexity or production-only size. Integration counts include Rust support modules and macro fixture sources.

Cratesrc files / linesIntegration and fixture files / linesResponsibility and audit focus
bombay-behavior10 / 6,84414 / 3,739Pure algebra, custody, structural composition, interpreter contracts
bombay-behavior-actors125 / 58,91342 / 35,188Catalogue policies, lifecycle state, ownership, public construction
bombay-behavior-macros1 / 1,5039 / 215Parsing, generated products, dependency resolution, diagnostics
bombay-behavior-testkit2 / 18230 / 7,435Independent oracles, finite driver, properties and compositions
behavior-mutants-gate1 / 2780 / 0Mutation verdict integrity; three inline unit tests

The fuzz manifest declares 21 binaries. Its target directory has 28 Rust files; the additional files include support modules and must not be counted as seven missing campaigns. The scheduled workflow currently lists all 21 binaries. There are also two benchmark programs and one core example.

Evidence labels used below:

  • Confirmed: directly visible in source or reproduced by a focused probe.
  • Coverage gap: the cited test or gate cannot establish the stated law; this does not by itself prove a production failure.
  • Design candidate: a bounded investigation with explicit acceptance criteria; it is not authorization to introduce a new abstraction.

Priority: P1 affects contract correctness or trust in verification; P2 affects maintainability, developer experience, or breadth of evidence; P3 is supporting cleanup. Check an item only after its completion evidence is recorded against a revision.

Behavior release boundary

This branch completes and releases the five Behavior workspace crates. A17's production Bombay interpreter witness and the PRD's Bombay/Address runtime packages follow the Behavior release against immutable published versions. They remain open handoff obligations with their original acceptance criteria; their absence must not be described as a passing downstream test or silently used to change the Behavior algebra. Finish the Behavior-owned A12, A13, and A20 reviews and required Behavior gates before merging this branch to main. The release workflow creates its version PR after successful main CI, then publishes from the versioned main revision. Record those CI and publication outcomes separately from the later Bombay integration result.

P1 — close contract and verification gaps

  • A01 — Reconcile creation, installation, and initialization ordering. Confirmed document conflict. docs/actor-transition-algebra.md, “Fresh creation,” orders initialization and its effects before installation. docs/atomic-runtime-settlement.md, “Initialization and activation order,” orders installation commit before the pure initialization fold, and describes InitializeWorker after ChildCreationOutcome::Established. actor/creation.rs::ChildCreationOutcome additionally represents initialization and host rejection before successful establishment. A runtime author cannot implement both descriptions as one unconditional order. Complete when: one normative contract distinguishes definition initialization, effect settlement, endpoint establishment, activation, and ordinary ingress; all canonical docs agree, and an interpreter trace proves the order plus each rejection and initialization-stop case. Any distinction between ordinary and atomic workers must be explicit and compositional. Classification: deliberate Bombay policy and derived composition, not a new actor-model guarantee. Resolve the law before changing production semantics.

  • A02 — Support ordinary, unrenamed Cargo dependencies in both macros. Confirmed source defect; external probe recorded below. behavior-macros/src/lib.rs::crate_path emits the name returned by proc_macro_crate. The manifests expose libraries named behavior and behavior_actors, while unrenamed package keys are bombay-behavior and bombay-behavior-actors. Facade resolution already compensates for this package/library distinction; direct dependency resolution does not. Current fixtures rename the direct dependencies, which avoids the failing case. Complete when: external consumers compile #[behavior] and #[pool_worker] with unrenamed dependencies, renamed dependencies, facade only, renamed facade, and direct plus facade dependencies. Preserve the existing missing-dependency diagnostic. Use a failing consumer fixture before editing expansion paths.

  • A03 — Restore logical-host projection through atomic actor products. Confirmed missing composition. actors/src/atomic/requests.rs derives send interpretation and settlement but not LogicalDeliveryProtocols. FifoRequests, KeyedRequests, FixedSupervisorRequests, and DynamicSupervisorRequests use this macro. The handwritten ProxyEffects also lacks this projection. There are no atomic implementations in actors/src/requirements.rs either. The current behavior-testkit/tests/logical_host_requirements.rs proves a synthetic DeliveryOutcomes tree, not these actual atomic families. Complete when: real FIFO, keyed, fixed, dynamic, and proxy compositions satisfy the documented projection, including transitive children and two wrapper orders. Assert exact ordered protocol products and duplicate occurrences. Audit CustomerDelivery and DiagnosticAction as part of the law: their logical routes must not disappear merely because they travel in InterpreterRequests, whose current projection is empty for every item. An empty blanket implementation is not a repair.

  • A04 — Make compile-denial tests fail for the intended reason. Confirmed false-positive examples. The ChildRoute compile-fail example in actors/src/composition/message_adapter.rs imports a removed type, so it does not prove rejection of a current creator-local capability. The ActivationPermit duplicate-move example in actors/src/atomic/worker/initialization.rs omits the required W: Behavior and endpoint bounds. It can fail before testing affine ownership. The incomplete-interpreter example in behavior/src/actor/creation.rs also used an implementation signature that obscured the missing child-host bound. Complete when: each safety fixture has a compiling lawful counterpart; one deliberate invalid operation produces the intended diagnostic. Exercise the counterfactual by removing that invalid operation or weakening the relevant invariant in an isolated probe. Keep removal-of-obsolete-name tests separate from capability-denial evidence. Rustdoc compile_fail alone proves that compilation fails, not why it fails.

  • A05 — Make the mutation verdict reject malformed and incomplete runs. Confirmed source defects; adversarial probe recorded below. mutants-gate/src/main.rs::usable rejects a failed baseline if present but does not require a successful baseline. tallies counts Failure and Success mutant outcomes toward completion while treating them as neither missed nor timed out. check matches counts per function, so duplicated outcomes can substitute for a different candidate in that same function. Three tests cover a clean run, a survivor, and a failed baseline only. Complete when: the gate verifies an explicitly supported baseline mode, exact candidate/outcome correspondence, valid outcome categories, missing and duplicate outcomes, unknown candidates, timeouts, viability collapse, stale baseline entries, malformed input, and command exit status. Include a case with a caught mutant plus a failed mutant at an otherwise satisfied floor. Reuse the report's actual candidate identity; function counts alone cannot prove campaign completeness.

  • A06 — Strengthen partial property-test oracles to complete observations. Coverage gap. In behavior-testkit/tests/catalogue_models.rs, the sequencer model checks delivery payloads and state, but not outcome messages, destinations, creation emptiness, or the next verdict. The order-gate model similarly checks selected deliveries. In catalogue_invariants.rs, successful configuration and readiness updates often check result.is_ok() and state, discarding successful Actions. Some deduplication checks inspect element zero without excluding extra elements. These tests are useful, but do not support the existing audit's claim of complete outputs after every step. Complete when: each generated step checks every declared effect lane, cardinality and order, destination, rejected owned input, and next verdict. Check initialization too. Use distinct owned payloads for custody-sensitive cases. Demonstrate failures for extra replies, wrong recipients, unexpected stopping, and dropped ownership; retain an independently structured oracle.

P2 — improve verification reach and remove repeated machinery

  • A07 — Extend mutation evidence to the actor catalogue. Coverage gap. Both mutation derivations in flake.nix select only --package bombay-behavior; test packages are core and testkit. They do not mutate bombay-behavior-actors or run its integration tests as a selected mutation test package. A strict core verdict says nothing about the largest crate's survivors. actors/tests/mutation_contracts.rs is an ordinary test file, not evidence of an actor mutation campaign. Complete when: independently reviewable actor-family campaigns exercise their relevant unit, integration, and model suites; survivors have a killed regression or a reviewed equivalence argument. Ratchet viability separately from mutant detection, and label coverage by crate and law. Fix A05 first. The current candidate listing for bombay-behavior-actors contains 3,125 mutations; no actor-wide campaign verdict is claimed by this branch. Verified selected-slice gate: nix build .#mutants-actors --no-link --no-write-lock-file passed four independently ratcheted actor campaigns. Health caught 7/7 viable mutations; WorkQueue caught 2/2 viable among four candidates; PubSub membership caught 6/6; publication caught 1/1 viable among five candidates. The remaining six whole-function replacements could not compile. All four reports had zero missed viable mutations and zero timeouts. mutants/actors/*.json records separate viability floors by function; the Nix command runs actor and testkit suites. Other actor laws retain their focused campaign evidence below, and A20 tracks their broader law coverage without claiming an actor-wide mutation verdict.

  • A08 — Make external-consumer and packaging gates exercise their claims. Confirmed gate gap. behavior-macros/tests/crate_resolution.rs::facade_package_sibling_targets_resolve_the_library_crate calls cargo check -p bombay-rs without --examples or --all-targets. The intended witness is fixtures/facade/examples/sibling_target.rs, which default cargo check does not select. The Nix package check only lists archive contents; the script's archive mode uses --no-verify. Complete when: explicit target selection checks the sibling example and both macro entry points; deliberately breaking that example breaks the gate. Build extracted published packages in a suitable release lane and compile a minimal consumer of the actual documented dependency declarations. Record package-content checks separately from package build verification.

  • A09 — Remove test-only indirection and unused test dependencies. Confirmed simplification. behavior-testkit/src/lib.rs::InitializeTest forwards unchanged to behavior_actors::Activate and adds a second spelling of the same operation. criterion is a dev dependency, but the benchmark is a handwritten main and no Rust source uses Criterion. Four testkit files contain 15 #[tokio::test] tests collectively and no .await at all: stash_properties, fsm_properties, compositions, and error_paths. Several destination-only fixtures implement an inert Behavior even though the route contract needs only Protocol. Complete when: callers import Activate directly, unused dependencies disappear from manifests and the lockfile where appropriate, synchronous tests use the ordinary harness, and destination fixtures keep only required capability implementations. Preserve fixtures whose actual purpose is to test behavior or creation. Report deleted surface and compile impact.

  • A10 — Define what the finite test driver preserves on error and in time. Confirmed limitation. behavior-testkit/src/lib.rs::drive returns only B::Error on a later failed transition, dropping accumulated successful effects and the active behavior. Trace also appends products lane by lane, losing the boundaries between turns. Interpreting that accumulated product afterward cannot establish per-turn runtime effect order. The error test fails on the first event and checks only the remaining mailbox length. Complete when: a success-success-error case exposes or explicitly documents the successful prefix's custody, and order-sensitive tests inspect per-turn actions or an independent interpreter trace. Do not describe the accumulation driver as a full runtime witness. Reuse existing action and settlement products if a richer error observation is needed.

  • A11 — Give named effect-product derivation one maintained implementation. Implemented and verified. Eleven generic named actor products now use SendProduct and #[behavior] generated products use the same procedural generators for send effects, logical-host projection, ordered interpretation, settlement classification, and source custody. The two settlement representations remain explicit. The old send_product! module, BufferSends, and atomic::request_product! were removed. requirements.rs retains only the exceptional ReplyDeliveries and HeterogeneousShutdownSends projections. The unused public behavior::settle_in_order tuple helper was removed after a source search found no Rust caller in this workspace or adjacent Bombay/Address repositories. Named products generate their ordered traversal directly; the normative settlement document states that law. Complete when: a law table compares complete equations before selecting shared machinery. A retained derivation must preserve semantic field names, declared order, corruption suffixes, source admission, and logical-host projection, and delete repeated implementations. Prove two unrelated real products and both wrapper orders before catalogue migration. Do not merge products with different ownership or retirement laws, or introduce a public product framework merely to save typing. Evidence: the equation inventory, two unrelated actor products, source-custody tests in both SendLayer orders, and workspace --all-targets tests support the retained design. A clean Nix gate on a8f15b7 passed all ten active aarch64-darwin checks, including 843/843 optimized Nextest tests.

  • A12 — Reassess aggregate decomposition using retained current values. Design candidate. FIFO's root has 4,097 lines, stable proxy's root 3,506, fixed recovery 3,080, and dynamic supervisor's root 2,839. These counts include comments and tests; they are review triggers, not evidence of redundant states. FIFO keeps most transition concerns at its visibility root, while fixed supervision spreads substantial transition authority among roster, recovery, start, outcome, and shutdown implementations. Several roots use mem::replace(..., Stopped) or a dormant placeholder during a transition. Complete when: each family has the full AGENTS aggregate-drift record, including before/after states, alternatives, branches, production lines, modules, public spellings, and the future-needed value in every subordinate alternative. Investigate direct owned-data joins and one commit point; preserve distinctions needed for rejection, concurrency, or terminal custody. Reduce responsibilities only where a falsifying law proves redundancy. Keep FIFO assignment policy and keyed binding policy distinct. Reviewed distinction: StableProxy's data-free Dormant and EmptyInitial states are not duplicate history labels. Dormant admits its one initial worker submission; EmptyInitial follows a rejected initial creation and rejects another submission with the observable Overlap and ProxyPhase::EmptyInitial. proxy_command_recovery and proxy exercise this path. Merging the states would admit a second initial worker or change the documented outcome. The other subordinate alternatives and family measurements still require the full A12 checkpoint. Dynamic supervision's WorkerChangeDisposition::{Committed,Cancelled} retains the answer to a future repeated cancellation. In DynamicEntryPhase::Available, the disposition selects the same committed or cancelled receipt again. dynamic::ready_service_accepts_one_replacement_on_its_current_proxy and dynamic::accepted_start_cancellation_retires_before_fresh_key_reuse exercise these answers. Deleting the disposition would change that later reply even though service availability is the same. This read-only distinction does not close the wider family audit. The stopped and forced-retirement alternatives in StableProxy, fixed supervision, FIFO, and keyed pooling still own workers, submissions, shutdown results, or rejection causes for terminal custody. Their fields have no local read path in some cases because the whole stopped behavior is retained for the interpreter. The downstream terminal-return witness in A17 and the interpreter ownership PRD must prove each transfer before any such alternative can be removed. This is a custody question left open by the source-only review.

    Decomposition baseline at e9c8d8c (read-only): the figures below count physical lines in each family source tree, including comments and embedded tests. Production lines exclude whole spans under #[cfg(test)] but retain comments and blank lines. Match arrows are a search diagnostic, not semantic transition branch counts.

    FamilyRoot control representationSource modulesPhysical linesProduction linesMatch arrowsStill required
    Stable proxyProxyState: 8 alternatives65,9465,076398Enumerate each nested shutdown and retirement value against exact terminal custody.
    Fixed supervisorFixedRoster: 5 alternatives; recovery owns a separate 2-way policy state1910,1049,512718Check roster/recovery joins and every retained prepared worker.
    Dynamic supervisorSupervisorAvailability: 2 alternatives; each keyed DynamicEntryPhase has 14 alternatives84,1204,020246Check whether per-key transitions remain an entity invariant rather than a second aggregate authority.
    FIFO poolPoolState: 5 alternatives54,7834,783311Check backlog, cursor, per-member custody and forced retirement separately.
    Keyed poolKeyedPoolState: 5 alternatives105,7555,536268Check binding generations and per-role order without importing FIFO policy.

    These sums have no proposed deletion yet. The source scan found no semantic bool field in these families; the observed boolean signatures are membership or equality predicates. The FifoDispatch alternatives that return the same queued job still select different lawful actions: unavailable worker may enqueue it, while exhausted assignment correlation returns an explicit rejection. Fixed recovery's LeaveEmpty and SourceUnavailable both retain recovery state but select a lifecycle fact versus exact input rejection. Those alternatives cannot be merged by payload shape alone. This baseline does not replace the future-needed-value and production measurements for every subordinate alternative; A12 remains open.

    A12 single-worker creation batch, pre-edit law: StableProxy stages one worker creation per start. Its creation settlement therefore consumes exactly one matching result; a zero- or multi-item settlement is an unexpected input that must return the complete original ordered batch to the owner while the proxy remains in its creating phase. This is Bombay's derived staged-creation correlation policy, not an actor-model allocation law. The public caller syntax and observable transition stay unchanged. The focused proxy_command_recovery malformed-batch regression covers the complete returned batch. Existing lower-order products are CreationSettlement, CreationsSettled, WorkerCreation::Unexpected, and the owner diagnostic; no new type, bound, port, or interpreter operation is needed. The candidate implementation uses the owned vector's exact-one conversion so a failed cardinality check returns every item without cloning or reconstructing a different batch. This local simplification does not close the family-wide A12 inventory.

    A12 single-worker creation batch, retained checkpoint: Root ProxyState remains 8 alternatives before/after; the touched WorkerCreation sum remains 3 and CreationSettlement remains 3. Its three top-level settlement branches and five reachable cardinality paths are unchanged; two impossible pop() == None branches are gone. The touched production method is 83 → 70 lines; the six-module family is 5,959 → 5,946 physical source lines, including unchanged embedded tests, and 5,089 → 5,076 production lines after excluding the 870 lines under #[cfg(test)]. Public spellings and module count are unchanged. WorkerCreation::Initializing still owns the committed worker, activation, and possible prior stop; WorkerCreation::Rejected owns the rejected worker, activation, and possible prior stop; WorkerCreation::Unexpected owns the pending worker, possible prior stop, and the entire anomalous batch for the owner diagnostic. No arrival-history label, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax was added. Cross-checked docs/actor-laws/proxy.md, docs/engineering/atomic-actor-essence.md, and docs/engineering/atomic-actor-retained-core.md; the focused 53-test proxy recovery suite passes. Disposition: pass for this local simplification; A12 remains open for the complete family inventory and terminal custody.

    A12 exact-one creation batch, pre-edit law: Actor research requires fresh creation but does not prescribe a Rust batch API. Bombay's ordered Creations<Item> is a derived effect product. A single-child aggregate may consume exactly one result; if the batch has zero or multiple items, the conversion must return the complete original batch in order. The intended caller syntax is creations.into_one(), returning Result<Item, Creations<Item>> without Clone. A focused external caller test will require one move-only item to succeed and empty/two-item batches to return intact; the prior API fails that test because it has no such operation. The existing lower-order value is the privately owned Vec<Item> in Creations; its exact-one array conversion already appears twice in StableProxy, while DynamicSupervisor manually checks length then has an unreachable empty branch. The design stage adds only the batch operation and its focused test. Separate migration stages will apply that proven operation to those two aggregates, preserving their current CreationSettlement outcomes and interpreter requirements. Before editing, the core batch has no state sum; StableProxy has eight root states and six modules, DynamicSupervisor has two root availability states, fourteen entry phases, and eight modules. No new actor state, effect lane, trait bound, interpreter capability, or type is proposed. The public batch method count grows by one in the design stage; branch and line measurements follow each retained stage. The external caller initially failed with three E0599 diagnostics at the intended into_one calls. After the core method was added, the focused Nix-pinned test passed for one, zero, and two move-only workers. The design stage adds 13 production source lines and 22 net test lines; it changes no aggregate state, subordinate alternative, transition branch, module, or interpreter path. On failure, the original Vec<Item> is returned inside the same ordered Creations value; there is no clone, dropped item, arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax. The actor transition and retained-core creation laws were cross-checked. Disposition: pass for the batch API; aggregate migrations and their separate checkpoints remain open. A12 exact-one aggregate migration, retained checkpoint: StableProxy now consumes rejected and settled worker batches through that operation. Its eight root states, three WorkerCreation alternatives, six modules, and public spellings are unchanged; the two cardinality success/failure choices are unchanged. Its production source falls by two lines, from 5,076 to 5,074. DynamicSupervisor now consumes its proxy-settlement batch through the same operation. Its two availability states, fourteen entry phases, eight modules, and public spellings are unchanged. The same reachable success/failure choice remains, while the old impossible next() == None branch after len() == 1 is gone. Its production source falls by five lines, from 4,020 to 4,015. The dynamic regression now checks empty and two-item rejection as the exact ProxyCreationsSettled event, including both untouched routes, creation IDs, kinds, item order, and the retained CreatingProxy phase; that test changes by +47/-3 lines. All 29 dynamic and 53 proxy recovery tests pass with the Nix toolchain. The full malformed batch remains owned by the rejected event, with no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller path. docs/actor-laws/proxy.md, docs/actor-laws/dynamic-supervisor.md, and the normalized atomic-actor documents were cross-checked. Disposition: pass for the mechanical migrations; the remaining family inventories and interpreter terminal custody still keep A12 open. A clean detached-worktree nix flake check -L --max-jobs 2 at 44922e2 passed all eight active aarch64-darwin checks, including 845/845 optimized Nextest tests, Rustdoc, Clippy, package, and formatting. The first run caught three test-only consuming calls inside assertions; those calls now execute before the assertions and the full rerun passes.

    A12 StableProxy root values, read-only review: at the e9c8d8c checkpoint the one control-state sum remained eight alternatives in six modules and 5,076 production lines. The retained values below are used by a later decision or returned as terminal custody; these rows do not claim that every nested sum has been reviewed.

    ProxyState alternativeExact current value required later
    DormantNo worker; the one initial submission is still admissible.
    StartingStart kind and current creation, initialization, activation, or return value select correlation, rejection return, and the next effect.
    ReadyThe exact current worker capability and attempts select service delivery, stop, and replacement.
    EmptyInitialNo worker; initial-start authority is spent, so another initial submission must return Overlap.
    EmptyAfterThe previous worker attempt is needed as replacement provenance.
    ReplacingThe predecessor departure or successor result plus outstanding shutdown correlation must be joined before publication.
    ShuttingDownUnresolved worker, creation, initialization, activation, and departure values must settle or transfer before retirement.
    StoppedProxyRetirement owns the exact residual values for the runtime custodian; A17/T16 must prove that transfer.

    WorkerStopping is a direct independent join: the shutdown request is either awaiting its exact ID or has its resolution, while the exact worker stop is absent or present. The resolved-plus-stopped combination immediately becomes StoppedWorker, so no extra arrival-order state is stored. proxy_command_recovery exercises stop-first and resolution-first joins. The root table and this join match docs/stable-proxy.md and docs/actor-laws/proxy.md; they justify retention, not a new deletion. The nested sums are inventoried next; other family inventories and the interpreter's terminal transfer still keep A12 open.

    A12 StableProxy nested values, read-only checkpoint: The current state.rs has the same eight root alternatives and sixteen subordinate sums with fifty alternatives as the earlier baseline. Across the six family modules, current source has 5,950 physical and 5,080 production lines, 398 => tokens as a search diagnostic, and fifteen top-level public declarations. This review changes none of those counts, no transition branch, and no public spelling. Each row names what a later transition or terminal custodian still needs; paired alternatives below have different legal next operations even where they carry the same payload shape.

    Subordinate sumAlternatives and future-needed current values
    PreReadyFailureInitializationEffects: failure plus activation plan; ActivationStart: complete request plus refusal; Activation: plan rejection. These select distinct owner outcomes after worker return.
    WorkerStartKindInitial: no predecessor; Replacement: replaced attempt plus predecessor shutdown status, selecting lifecycle provenance and join.
    PredecessorShutdownSettled: no outstanding shutdown; Awaiting: exact shutdown ID to match its later resolution.
    ReplacementCompletionReady: current worker plus result; ReadyAfterStop: worker attempt, result, exact stop; Empty: worker attempt plus result. Each joins a predecessor shutdown differently.
    ProxyReplacementReturningPredecessor: predecessor departure, pending successor, staged creation; SuccessorResultAwaitingShutdown: replaced attempt, shutdown ID, successor completion.
    ActivationProgressWaitingForStart and Running each retain the exact activation attempt; only Running has admitted Started, so readiness can be consumed there.
    ActivationDuringDeparturePending: activation progress still awaiting input; Returned: completed activation value owed at retirement.
    WorkerActivationShutdownDeparting: activation state plus worker departure; WaitingForActivation: activation progress, current worker, optional shutdown resolution, exact stop.
    WorkerStartPhaseCreating: pending worker and optional early stop; Initializing: committed worker and optional stop; Activating: committed worker, progress, optional stop; ReturningWorker: departure and precise pre-ready failure.
    WorkerInitializationShutdownDeparting: optional returned initialization value plus worker departure; WaitingForInitialization: worker, optional shutdown resolution, exact stop.
    WorkerInitializationRetirementInitialized: permit plus plan; EffectsRejected: failure plus plan; Stopped: plan plus optional earlier initialization stop.
    WorkerActivationRetirementStartRejected: complete request plus refusal; Ready: readiness value; Rejected: application rejection.
    WorkerStartRetirementResult: start result; Initialization: initialization retirement, worker, optional shutdown resolution, stop; Activation: activation retirement, worker, optional resolution, stop; ReadyWorker: result plus returned worker; ReplacementCompletion: exact successor completion.
    ProxyRetirementEmpty: optional previous attempt; ReplacementCancelled: replaced and successor attempts plus predecessor; Worker: returned worker; WorkerStart: optional replaced attempt plus start retirement; ReplacementAfterPredecessor: replaced attempt, predecessor resolution, start retirement. These are whole stopped-state custody.
    ProxyShutdownStarting: start state; ReturningWorker: departure; ReturningWorkerStart: kind, departure, failure; ReturningPredecessor: departure and both attempts; ReturningSuccessor: replaced attempt, predecessor return, successor departure and result; Initializing: kind and initialization shutdown; Activating: kind and activation shutdown; WaitingForPredecessor: replaced attempt, shutdown ID, start retirement.
    PredecessorReturnAwaiting: shutdown ID; Returned: exact shutdown resolution.

    The subordinate sums store current affine custody and correlation, not an independently dispatched behavior. Optional stops and resolutions mean exactly absence or presence of one fact; they do not encode mutually exclusive aggregate phases. No arrival-history-only alternative, repeated failure cause, false worker cardinality, nested transition authority, semantic boolean, or structural user syntax was found. The actor transition law, proxy law, stable-proxy guide, and normalized atomic documents were cross-checked. Disposition: pass for the StableProxy source model; A12 remains open for the other families and downstream terminal custody. A clean detached-worktree nix flake check -L --max-jobs 2 at 7574bcb passed all eight active aarch64-darwin checks, including 845/845 optimized Nextest tests, Rustdoc, Clippy, package, formatting, audit, and deny gates.

    A12 shared pool assignment join, read-only review: FIFO and keyed pools both use the four-alternative private AssignmentDelivery sum. This is one current job obligation with an exact assignment correlation; it is not a second actor transition authority. The owning aggregate still selects the complete Actions. The shared assignment module has 811 production lines and 311 embedded-test lines; this review changes zero states, alternatives, transition branches, modules, production lines, or public spellings.

    AssignmentDelivery alternativeExact value needed by a future decision
    AwaitingReceiptNo delivery receipt exists; completion or stop must be retained until acceptance or rejection settles the moved assignment.
    AcceptedThe exact receipt has committed delivery; the next matching completion or stop can select the one customer disposition.
    CompletionHasPriorityThe completion is authoritative if delivery is accepted; an optional later exact stop must still drive worker recovery once.
    WorkerExitHasPriorityThe exact stop is authoritative if delivery is accepted; an optional later completion must remain available for stale or contradictory settlement.

    CompletionHasPriority and WorkerExitHasPriority are observable order decisions, not duplicate arrival labels. Collapsing them into a product of two optional facts would lose which terminal event won. The two focused atomic::pool::assignment order tests and the FIFO/keyed pool law documents cross-check the retained values. AssignmentReceiptOutcome, WorkerCompletionOutcome, AssignmentRejectionOutcome, and WorkerExitOutcome return different complete values to their respective callers; they have not been merged by their common job fields. This review finds no semantic boolean, repeated cause, false cardinality, structural caller path, or redundant nested actor. Disposition: pass for this shared join only; both pool families' member, recovery, and retirement sums remain under A12 review. The PRD now states FIFO's clone-and-retry policy explicitly.

    A12 FIFO/keyed root values, read-only review: each pool has one five-alternative root sum. This review changes zero states, subordinate alternatives, transition branches, production lines, modules, or public spellings. FIFO remains five modules and 4,783 production lines; keyed remains ten modules and 5,536 production lines. The exact future-needed values differ inside their operating products:

    Root alternativeFIFO current valueKeyed current value
    ConstructedThe ordered prepared worker roster must be returned intact if initialization ID reservation fails.The same prepared roster must survive failure before the per-role queues and binding table exist.
    OperatingFifoOperating owns the ordered members, admission-ordinal backlog, and next role cursor. These select a global FIFO dispatch.KeyedOperating owns one queue per role, current worker cells, and the bounded key binding table with generations. These select exact key affinity.
    Draining / RetiringThe exact unresolved RetiringWorker vector and ShutdownDeadline settle worker results and a bounded drain.The same shared worker-retirement values and deadline settle keyed drain; key/queue outcomes are emitted when retirement begins.
    StoppedWhen committed, no worker or job remains in the actor root and later input is rejected; it is also the temporary replacement during a consuming transition.When committed, no worker or binding remains in the actor root and later input is rejected; it is also the temporary replacement during a consuming transition.
    ForcedRetirementThe unresolved workers and exact cause (WorkerShutdownIdsExhausted, DeadlineNotScheduled, or DeadlineElapsed) must transfer to the runtime custodian.The same kind of unresolved worker vector and exact cause must transfer; the per-role binding policy does not turn that into a FIFO backlog.

    Constructed is a pre-initialization ownership phase and ForcedRetirement is terminal residual custody, not duplicates of the operational Stopped state. Both are source-level extensions to the three-state operational sketches in the normalized FIFO/keyed law documents; those documents now name the distinction. Existing FIFO forced-retirement tests and keyed lifecycle tests check retained workers locally. They do not prove the parent-to-root transfer, which remains A17/T16 work. The source scan found no arrival-history root alternative, repeated cause, false role cardinality, nested actor authority, semantic boolean, or positional caller syntax. Disposition: pass for these root sums only; member, recovery, deadline, and terminal-custody alternatives remain under A12 review.

    A12 fixed supervisor root/recovery values, read-only review: the root FixedRoster remains five alternatives in nineteen modules and 9,512 production lines; SupervisorRecoveryState remains a separate two-way policy sum. This review changes zero states, alternatives, transition branches, production lines, modules, or public spellings.

    ValueExact current value needed by a future decision
    FixedRoster::NewThe ordered prepared worker roster either stages one proxy per role or returns complete members on creation-ID exhaustion.
    FixedRoster::OperatingThe ordered RosterOwner cells retain exact proxy, worker, pending preparation, and recovery obligations for role decisions.
    FixedRoster::ShuttingDownFixedShutdown retains the unresolved roster and shutdown joins while late exact facts continue to settle.
    FixedRoster::TerminatingExact owners and prepared submissions survive a terminal diagnostic or forced end for runtime custody; A17/T16 must prove transfer.
    FixedRoster::StoppedWhen committed, no roster value remains and new events cannot be accepted; it is also the temporary replacement during a consuming transition.
    SupervisorRecoveryState::AutomaticStrategy, eligibility, restart budget, correlation, and WorkerSourceCustody select a lawful preparation or denial.
    SupervisorRecoveryState::TemporaryAutomatic restart authority is absent; a worker stop leaves the role empty.

    Within automatic recovery, WorkerSourceCustody::Available owns the concrete source, PreparingWorkers means the in-flight request owns it, and Retirement owns the exact returned source value. These are current ownership positions, not three records of arrival history. RecoveryChoice::LeaveEmpty and SourceUnavailable both return recovery state but produce different observable outcomes: the former is the selected policy decision, the latter rejects a new preparation because the source is already transferred or retired. The fixed-supervisor initialization and recovery suites cover those distinctions locally. The normalized fixed supervisor law and retained-core document were cross-checked. The residue scan found no new arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller path. Disposition: pass for these root/recovery sums only; individual roster owner, shutdown, preparation, and terminal-custody alternatives remain under A12 review.

    A12 dynamic supervisor entry values, read-only review: the aggregate has one SupervisorAvailability sum with Accepting(ActorDrainPolicy) and ShuttingDown(ShutdownDeadline). It owns a key map of DynamicEntry values; each entry retains its exact creation, generation, operation, and one of fourteen DynamicEntryPhase alternatives. The entry module provides status and shutdown projections but does not implement Behavior or choose the aggregate Actions. This review changes zero states, alternatives, transition branches, production lines, modules, or public spellings. The family remains eight modules and 4,015 production lines after the exact-one batch migration.

    DynamicEntryPhase alternativeExact current value needed later
    CreatingProxyThe untransferred worker submission is returned on stop or cancellation, or sent to the committed proxy after its birth.
    ShuttingDownProxyCreationThe enclosing creation correlation remains pending; a committed proxy must be drained and a rejected birth must retire with shutdown provenance.
    DrainingProxyCreationStopThe same birth correlation remains pending, but a rejected birth must retire as an explicit stop. This cause changes the lifecycle report.
    WaitingForActivationThe exact established proxy and still-owned worker submission await activation capacity.
    WaitingForProxyInputThe exact proxy and input witness await ownership settlement of the initial operation.
    WaitingForProxyOutcomeThe proxy and accepted operation ID await the later initial worker result.
    CancellingProxyCreationThe enclosing creation and operation correlations remain after the worker was returned; a later committed proxy still requires retirement.
    StoppingProxyCreationThe original start operation and untransferred submission must be returned by explicit stop while proxy birth still settles.
    AvailableThe exact proxy, ready-or-empty service value, and latest committed-or-cancelled disposition answer service and repeated cancellation queries.
    ReplacementQueuedThe current service and successor submission coexist until capacity permits transfer.
    ReplacementAwaitingReceiptCurrent service, exact proxy, and witness await successor input acceptance or rejection.
    ReplacementAwaitingOutcomeCurrent service, exact proxy, and accepted operation ID await replacement outcome.
    StoppingThe proxy, restorable service, shutdown settlement, and optional exact stop must join before stop completes or rolls back.
    RetiringProxyRetirement owns the exact proxy, shutdown and transferred-input custody, and possible stop through terminal drain.

    The three data-free creation phases still have the enclosing entry's correlation values and distinct future lifecycle outcomes; merging them by payload size would erase shutdown, explicit-stop, or cancellation cause. The dynamic-supervisor law and normalized atomic documents were cross-checked against the source and local dynamic tests. No arrival-history value without a future decision, duplicated cause, false key cardinality, nested actor authority, semantic boolean, or structural caller syntax was found in these phase sums. Disposition: pass for the entry and availability sums only; nested retirement, operation, and terminal transfer still keep A12 open.

    A12 shared pool member and recovery checkpoint, read-only: FIFO and keyed pooling share the current member/assignment ownership model, but each root selects its own queue policy. MemberState has four alternatives, WorkerPhase seven, RecoveringWorker four, ShutdownJoin three, RetirementStatus five, WorkerStartupCustody five, WorkerShutdownStatus two, PoolRecoveryState three, and WorkerRecoverySource two. The shared pool subtree has six modules, 3,760 physical lines, 3,414 production lines, 198 match arrows, and twelve top-level public declarations. This read-only batch changes zero control states, subordinate alternatives, transition branches, lines, modules, or public spellings.

    Current sumExact value needed by its next owner
    MemberState::{Creating,Worker,Recovering,Retired}The pending birth with activation and possible early stop; the established worker phase; the previous attempt plus recovery work; or absence of a live role.
    WorkerPhase::{Initializing,WaitingForActivation,ActivationDispatched,Activating,Idle,Busy,Stopping}Initialization correlation and possible stop; exact permit and plan; dispatched or accepted activation attempt with possible stop; available worker; one assigned job obligation; or the exact shutdown join. Dispatch and acceptance select different later acknowledgements.
    RecoveringWorker::{WaitingForSource,Preparing,Scheduling,WaitingForTimer}Previous attempt and stop, plus respectively unavailable source, preparation ticket, pending replacement and timer, or the same replacement awaiting its timer. The latter two distinguish whether schedule admission still has to settle.
    ShutdownJoin::{AwaitingBoth,AwaitingStop,AwaitingSettlement}Exact shutdown ID; accepted shutdown resolution awaiting stop; or exact stop awaiting settlement. Either arrival order must reunite both facts once.
    RetirementStatus::{AwaitingCreation,Established,AwaitingPreparation,AwaitingRestartSchedule,Drained}Pending birth; current worker, optional startup and shutdown join; prior stop with preparation ticket; pending replacement with timer; or no remaining worker custody.
    WorkerStartupCustody::{ActivationPlan,Initializing,ActivationPermit,ActivationStart,Activation}Respectively untransferred plan, initialization attempt, permit with plan, dispatched start, or accepted activation correlation returned during retirement.
    WorkerShutdownStatus::{NotRequested,Waiting}No shutdown authority yet, or the exact outstanding join.
    PoolRecoveryState::{Permanent,Transient,Temporary} and WorkerRecoverySource::{Available,AwaitingReturn}Permanent/transient retain source, limit, release and failure policy; temporary has no source and retains failure policy. Available owns the concrete source; awaiting return records that the preparation request currently owns it.

    WorkerRecoveryDecision, WorkerCustody, RetirementReturns, and the event-specific retirement outcomes are consuming transition products, not independently stored actor control states. Their distinct payloads return exact source, worker, assignment, or replacement custody to the root. A product of optional values would allow a worker to be both idle and busy or lose which shutdown fact remains; a direct vector already represents the ordered role roster. The normalized FIFO/keyed laws, actor transition law, and runtime settlement law were cross-checked. No arrival-only state, duplicated cause, false role cardinality, nested behavior authority, semantic boolean, or structural caller syntax was found. Disposition: pass for the shared member/recovery source model.

    A12 keyed binding checkpoint, read-only: RoleCell owns one role's member, admission-ordinal queue, and capacity. BindingTable owns bounded key-to-role bindings and a checked generation sequence. AdmissionBinding has two short-lived alternatives: Retained keeps the submitted key and existing evidence, while Reserved owns the fresh table reservation until admission commits or returns the key. BindingExpectation::{Absent,Exact} distinguishes a missing binding from one exact generation; the three BindingReservationRejected reasons return the same key with distinct capacity, conflict, or sequence-exhaustion causes. These are current authority/return values, not another keyed actor. Keyed pooling remains ten modules, 5,755 physical and 5,536 production lines, 268 match arrows, and twenty top-level public declarations before and after this review. Root states, subordinate alternatives, transition branches, and public spellings change by zero. The normalized keyed law and binding generation tests were cross-checked; the residue scan found no arrival history, duplicate cause, false cardinality, nested transition authority, semantic boolean, or structural caller path. Disposition: pass for source binding custody.

    A12 fixed roster and dynamic retirement checkpoint, read-only: Fixed supervision remains nineteen modules, 10,104 physical and 9,512 production lines, 718 match arrows, and twenty-seven top-level public declarations. Dynamic supervision remains eight modules, 4,115 physical and 4,015 production lines, 246 match arrows, and twenty-five such declarations. Both roots, all subordinate sums, transition branches, lines, modules, and public spellings are unchanged by this review.

    Current sumExact future-needed value
    RosterOwner::{Starting,Stopping,Online,Empty,Recovery,Unrecovered,Retired}Respectively a proxy start correlation; proxy shutdown join; established proxy, worker and readiness; empty role identity; recovery batch/preparation; unrecovered worker and reason; or terminal returned proxy custody. Its status projection does not select aggregate Actions.
    ProxyStartingMember six alternativesPending creation with original operation; established proxy awaiting authorization; dispatched input witness; accepted input ID awaiting outcome; exact rejected input; or exact rejected birth. Each has a different next input or return value.
    RecoveryRosterOwner::{Preparing,Admitted} and RecoveryMember::{Waiting,Replacing}Preparation owns the source/ticket; admitted batch owns prepared participants. A waiting member owns an untransferred submission; replacing owns an established proxy and exact replacement result.
    RecoveryParticipant::{Stopped,InitialInputDispatched,AwaitingInitialOutcome,Online}Original stopped member; proxy with dispatched input witness; accepted operation ID; or current ready member.
    ReplacementResponse::{InputPending,OutcomePending,OutcomeReturned,InputRejected}Exact input witness, accepted operation ID, returned outcome, or returned operation with rejection reason. RestartReleaseState::{Ready,Scheduling,Waiting} likewise distinguishes no timer from timer admission and an admitted timer.
    Fixed ProxyShutdown::{Dispatched,Accepted,Rejected}Unsettled input witness, accepted operation ID, or complete rejected shutdown. An optional exact ChildStopped in the containing member joins independently.
    Dynamic ProxyShutdown::{AwaitingSettlement,Accepted,Rejected}Pending shutdown witness, accepted operation ID, or rejection; the entry's stop remains independently correlated.
    Dynamic RetiringWork six alternativesDistinct start failure, unexpected stop, interrupted start, supervisor shutdown with optional service, cancelled returned worker change, or transferred proxy input with exact purpose and custody. These causes select different public lifecycle reports.
    Dynamic ProxyInputPurpose four alternatives and ProxyInputCustody four alternativesThe purpose distinguishes cancellation, interrupted start, initial start, and replacement with service. Custody distinguishes unadmitted witness, accepted operation, rejected input, and returned proxy outcome. The pair determines exact terminal return without replaying a control.

    Fixed recovery policy, dynamic key/operation correlation, source ownership, and the five normalized atomic laws were cross-checked with the source. Data-free retirement causes are observable lifecycle policy, and separate accepted-input versus returned-outcome states are needed to prevent false readiness/restart. No arrival-only state, repeated cause, false worker/key cardinality, nested Behavior implementation, semantic boolean, or structural application syntax was found. Disposition: pass for these source-level subordinate sums. Terminal transfer and caught-panic ownership remain the real-runtime A17/T16 witness; this review makes no claim about those downstream effects.

    A12 final source-review disposition: pass. The five root control sums, the StableProxy nested sums, the shared worker/recovery joins, keyed binding, fixed roster/recovery, and dynamic entry/retirement sums above retain exact values used by later decisions or returned in terminal custody. The before/after production source and syntactic branch counts are identical for each read-only family checkpoint; the earlier exact-one changes record their separate reductions and branch deletions. Counts, module ownership, public spellings, residue scans, and normalized-law cross-checks are recorded at each checkpoint. Earlier statements that A12 was open describe the staged review at those revisions. No state or module deletion is justified by a falsifying law, so none is proposed. Actual parent-to-root terminal transfer and post-commit panic limits are interpreter obligations in A17 and the PRD, not source-level aggregate-decomposition claims.

    FIFO and keyed pools each move their root state out with mem::replace(..., Stopped) during initialization and transition; fixed supervision similarly substitutes Stopped or a temporary recovery value, and StableProxy substitutes Dormant during one consuming transition. Normal return commits the result once, but a caught pure-fold panic before that commit may leave only the placeholder in the actor while owned state unwinds. This is an inference from the source, not a proven runtime outcome. The PRD's T16 panic and root-custody witness must test it before these sites can be called safe or refactored. A passing ordinary transition suite cannot decide that law.

  • A13 — Audit public bounds, hidden exports, and extension ownership. Confirmed surface requiring review. The current source has 10 #[doc(hidden)] annotation sites in core and 22 in actors, including members and re-exports. The public-surface inventory classifies each site by contract owner. These annotations do not make an item private. Conversely, an associated type mentioning a value does not by itself justify exporting it. Some Protocol impls carried transition-related bounds: Cache required K: Clone + Eq and V: Clone; Resolver required K: Clone + Eq before the focused A13 repair below. The four timer wrapper structs already have only one generic parameter, B; their effect signatures project address, phase, sends, and births from it, so they are a successful example rather than a gap. Complete when: classify each public item as application API, generated code obligation, or runtime port; identify each trait's lawful implementors. Move bounds only after caller-facing compile witnesses prove the narrower law. Measure diagnostics and compile cost. Document required runtime ports openly and keep representation private where Rust permits. Add no aliases, defaults, visibility, or generic parameters solely to silence the compiler. Progress: the public-surface inventory now accounts for all 78 top-level public traits by lawful implementor role, including the later ProxyControlAdmission interpreter port. Its actor-suite implementors and the isolated Bombay source identify its owner; the latter is not yet a successful A17 runtime witness. The inventory confirms that StashStatus has multiple real wrapper implementations; its name alone is not grounds for deletion. Externally authored child roles and generic logical-host owners have compile witnesses for the newly visible types. The inventory now classifies the hidden ChildProduct::stage method as a sealed structural conversion: only NoChildren and ChildCons implement the trait, Children::into_creates is its sole production caller, and the interpreter consumes the resulting Creations effect. Calling stage a runtime port had overstated its public contract. This correction changes zero Rust items, bounds, states, branches, modules, or public spellings. The cache/resolver protocol-bound comparison found no material compile-time difference in its measured pair; the caller diagnostics improved. The protocol-only caller now covers 20 catalogue actors, keeping construction and transition bounds at the operations that need them. A separate caller now proves that 14 unwrapped catalogue actors expose their read-only BehaviorBase projection without requiring the cloning, comparison, or ordering used only by construction or transition. This also includes keyed Deduplicator and OrderGate and a priority queue with opaque priority data. The proxy operation ID is now crate-private; focused external fixtures distinguish forbidden ID naming, receipt construction, and double settlement. Review of remaining hidden runtime ports and the rest of the public surface is still required. A repeatable cold actor-library check on aarch64-darwin used the same Nix-pinned Cargo 1.95.0 and two separate fresh targets per revision: main@435560c took 184.54/180.09 seconds and this branch at 1aeaed1 took 4.46/3.97 seconds. The actor .rmeta sizes were 27 MiB and 5.8 MiB. The measurement record gives the command and scope. This is a whole-branch comparison, not causal evidence for any one A13 bound; future bound edits still need focused caller diagnostics and their own cost check. A post-repair source scan of catalogue Protocol and BehaviorBase impl headers found no remaining copying/comparison/ordering bounds except Router's Route: Clone + PartialEq, which is also required by its current RoutingStrategy<Route> contract. Changing that contract would require a distinct membership and policy law, not a mechanical bound deletion. The read-only Router review found no legitimate transition for a route without identity comparison: new removes duplicates, Add/Remove select exact members, and selection clones the policy candidate so a failed route leaves it unchanged. A logical or established route whose endpoint lacks equality cannot currently satisfy that membership law. Narrowing only the protocol/base headers would create a nameable router that cannot be constructed or run; no bound edit was retained. Round-robin's cursor repair and the least-loaded/Rendezvous traces exercise the current comparable-route contract. This resolves the isolated header question, while A13's broader hidden-port review remains open.

    Pre-edit A13 transferable-route owner law: Logical, established, and mixed reply routes are transferable acquaintances. For any actor Owner, DeliveryRoute plus its associated protocol address equal to BehaviorAddr<Owner> already proves that the emitted delivery belongs to the owner's address namespace. The separate sealed DeliveryRouteFor<Owner> duplicates the same three implementations and forwards every deliver_for call to DeliveryRoute::deliver; no production consumer uses it. The only external caller is behavior-testkit::owner_scoped_delivery. This is a derived static composition law, while excluding creator-local ChildRoute from a standalone transferable route is a deliberate Bombay policy. Before deleting the trait, change that test's generic caller to use the associated address equality and preserve its logical/exact/mixed outcome assertions. Add a negative compile fixture that rejects naming the redundant trait; the fixture must fail on the prior public API for that exact name. The lower-order DeliveryRoute, Recipient, EstablishedRecipient, ReplyRoute, and their concrete send products remain. No new wrapper, route variant, runtime lookup, or child-binding capability is proposed. The negative rustdoc fixture failed on the prior API because its old-trait name still compiled. After deletion, that fixture and the existing wrong-protocol fixture pass, and the external owner-scoped delivery caller passes in debug and optimized builds with the associated-address bound for logical, exact, and mixed routes. The three touched production Rust files fall from 686 to 608 physical/production lines; the public trait count falls from 78 to 77. Root control states, subordinate alternatives, actor transition branches, and modules remain unchanged. The only removed public spelling is DeliveryRouteFor; existing route ownership stays with each concrete capability and its send product. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The actor transition law, composition guide, and normalized atomic documents were cross-checked. Disposition: pass; this is a deliberate source-breaking interface deletion and requires the release PR's breaking-change label. A13 remains open for the remaining surface review.

    Pre-edit A13 returned-worker custody documentation law: A host rejection of a staged worker returns WorkerCreationRejection::HostRejected containing WorkerRecovery<W>. Its consuming into_retirement() returns the exact current worker and untouched initialization actions to the custodian; no replacement worker or reconstructed actions are permitted. A committed worker outcome separately carries opaque WorkerAttempt evidence whose creation() projection is only creator-local correlation. These are existing derived ownership contracts. The external proxy_command_recovery::host_rejection_keeps_worker_and_initialization_actions_together case consumes WorkerRecovery, and proxy/fixed-supervisor callers name WorkerAttempt. Before editing, Nix-pinned Rustdoc omits both structs from the atomic index and has no item pages. The focused regression is visible pages and methods while those external callers continue passing. Only documentation hiding on these already-public types/methods and their grouped re-export may change; their private constructors, fields, result types, actor states, transition branches, and interpreter operations stay unchanged. Post-edit, Nix-pinned Rustdoc lists both types on the atomic index with item pages and shows into_retirement() and creation() on those pages. The focused external host-rejection test passes. Actor hidden annotation sites fall from 54 to 50. Root control states, subordinate alternatives, transition branches, modules, and public Rust spellings remain unchanged; the two touched Rust files fall from 440 to 436 lines as four hidden markers are removed. This edit changes documentation visibility only. WorkerRecovery still owns the rejected worker and all unattempted initialization actions, while WorkerAttempt still owns only exact issued correlation. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The creation/lifecycle law, stable-proxy guide, and normalized atomic documents were cross-checked. Disposition: pass for this custody documentation port; A13 remains open for the wider surface review.

    Pre-edit A13 worker initialization and activation port law: A host receives the exact InitializeWorker request, observes its established target and correlation, and consumes it once to produce a complete WorkerInitializationReport. A successful report alone carries the ActivationPermit that can construct BeginActivation; the interpreter admits Started before polling the plan and returns the exact WorkerActivation result. These are existing derived custody and ordering contracts, not new runtime effects. External proxy_command_recovery, stable_proxy_shutdown_model, fifo_pool, and interpreter-contract caller tests already name these concrete types and exercise accepted, rejected, stopped, and activation-start-rejected paths. Before editing, Nix-pinned Rustdoc omits the initialization and activation items and their public methods from the atomic pages because their declarations and grouped re-export are hidden. The focused regression is complete visible Rustdoc for the already-public host and owner methods while the external transition suites retain their results. Only documentation hiding may change; private constructors, fields, correlation tokens, return types, effects, states, branches, and interpreter ordering remain as before. Post-edit, Nix-pinned Rustdoc lists all nine named types on the atomic index with their existing public method pages. The external proxy recovery and shutdown model suites pass 53 and 7 tests. Actor hidden annotation sites fall from 50 to 23. The three touched Rust files fall from 755 to 728 lines by deleting 27 hiding markers. Root control states, subordinate alternatives, transition branches, modules, and public Rust spellings are unchanged. The worker request still owns its exact target, worker attempt, initialization attempt, and affine activation plan; the permit still authorizes just that worker and attempt; the returned activation still owns its original result or rejection. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The actor creation/lifecycle law, stable-proxy guide, and normalized atomic documents were cross-checked. Disposition: pass for this visibility batch; A13 remains open for the other hidden ports and the full public surface review.

    Pre-edit A13 creation-observation port law: A local interpreter may observe the exact same-action child creation named by protocol, occurrence, and creator-local CreationId. The public ObserveCreation<P, Occurrence> request carries that typed prerequisite; it does not establish freshness or let a foreign child protocol substitute because its payload shape matches. This is an existing Bombay observation policy. External creation_observation_settlement and child_shutdown_interpretation callers already name and interpret the request, while its Rustdoc compile-fail fixture rejects a different protocol. Before editing, Rustdoc hides the existing item page. The focused regression is a visible request page and retained external and compile-fail results. Only its documentation marker may change; request fields, constructor, prerequisite, effect order, behavior state, and interpreter semantics remain unchanged. Post-edit, the actor Rustdoc index links to ObserveCreation and its new method. The two external caller suites pass 5 tests and actor doctests pass 44, including the wrong-protocol compile-fail example. Hidden actor annotation sites fall from 23 to 22; the touched production file loses one marker line. Control states, subordinate alternatives, branches, modules, and public Rust spellings stay unchanged. The request retains the same exact typed prerequisite and current creation ID. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The actor creation/lifecycle law and normalized observation document were cross-checked. Disposition: pass for this runtime-port documentation; A13 remains open for the broader surface review.

    Pre-edit A13 proxy outcome and correlation documentation law: A caller inspecting an initial or replacement proxy result must distinguish WorkerStartResult::CreationRejected from Ready and Unavailable; the latter owns the exact ProxyDrain cause and worker lifecycle values. A trusted interpreter inspecting ProxyOperation must read its exact creator-local creation correlation before admitting private control. These are existing derived ownership contracts, not additional actor powers. External proxy, fixed-supervisor, and dynamic-supervisor tests already match these products and call ProxyOperation::creation(). Before editing, Nix-pinned Rustdoc omits WorkerStartResult and ProxyDrain from the atomic index and has no item pages; it also omits method.creation from the visible ProxyOperation page. The focused regression is their visible Rustdoc contract with those existing external callers still passing. The edit removes documentation hiding from the domain outcome, exact correlation method, and their grouped re-export; it does not add a Rust spelling, constructor, capability, bound, lane, state, or transition. Post-edit, Nix-pinned Rustdoc lists ProxyDrain and WorkerStartResult in the atomic index with item pages and lists method.creation on the ProxyOperation page. The focused external proxy, dynamic-supervisor, and fixed-supervisor suites pass 53, 29, and 98 tests. Actor hidden annotation sites fall from 56 to 54. StableProxy's eight root states, the fixed roster's five, and the dynamic entry's fourteen alternatives remain unchanged; their branches, modules, production public spellings, and ownership values are unchanged. ProxyDrain still owns one precise committed-worker failure cause, and creation() still exposes only the creator-local correlation. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The proxy law, stable-proxy guide, and normalized atomic documents were cross-checked. Disposition: pass for these visible contracts; A13 remains open for the wider surface review.

    Pre-edit A13 customer-delivery documentation law: A keyed-pool interpreter must name the concrete CustomerDelivery<P> action to return both the attempted delivery and original customer route on rejection. An assignment interpreter must call AssignWorker::target() to obtain a clone of the exact worker recipient before consuming settle. These are existing derived ownership ports, not new actor powers. The public caller syntax is already exercised by the keyed-pool external compile suite and the interpreter-contract assignment fixture; the four customer alternatives retain their existing complete settlement equation. Before editing, Nix-pinned Rustdoc omits CustomerDelivery from the atomic index and has no item page, and omits method.target from the visible AssignWorker page. Removing their two declaration markers and separating the existing grouped re-export exposes only those already-public names. The focused regression is their Rustdoc visibility with the existing external callers still passing. No constructor, method, bound, trait, effect lane, control state, transition branch, or interpreter operation changes. Post-edit, Nix-pinned Rustdoc lists CustomerDelivery in the atomic index, generates its item page, and lists method.target on AssignWorker. The 23 keyed-pool tests and three external assignment-delivery tests pass. Actor hidden annotations fall from 58 to 56; the two declaration markers are gone while the sealed CompletesAssignments re-export remains hidden. The root aggregate states, subordinate alternatives, transition branches, source modules, and Rust public spellings are unchanged. The exact worker recipient capability remains inside AssignWorker, and the original customer route remains inside a rejected CustomerDelivery. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The keyed-customer rejection law in docs/atomic-runtime-settlement.md and the normalized pool law were cross-checked. Disposition: pass for these two visible ports; the wider A13 surface and compile-cost review remain open. A clean detached-worktree nix flake check -L --max-jobs 2 at 19a38c2 passed all eight active aarch64-darwin checks, including Rustdoc and optimized Nextest.

    Pre-edit A13 diagnostic-port visibility law: An external interpreter must name the concrete DiagnosticAction, DiagnosticAccepted, and sealed DiagnosticRoute contract to settle a routed or terminal diagnostic. The accepted value either records delivery or transfers the exact diagnostic into terminal custody; it cannot silently discard the latter. This is a derived interpreter ownership port, not a new actor transition. The external diagnostic_action and interpreter-contract source_free_custody suites already use this syntax, including the constructor methods. Before editing, Nix-pinned Rustdoc builds but omits all three names from the atomic index and has no item pages for them. The focused regression is visible Rustdoc for these already-public names and methods while the existing caller suites continue to pass. The only proposed change removes documentation hiding annotations on the three declarations, their four methods, and grouped re-export. It adds no type, bound, capability, effect lane, or transition branch. Post-edit, Nix-pinned Rustdoc lists all three names in the atomic index, generates their item pages, and lists all four methods. The three diagnostic_action tests and four external source-free custody tests pass. Actor hidden annotations fall from 66 to 58. Aggregate control states, subordinate alternatives, transition branches, modules, and Rust public spellings are unchanged; the documentation-only edit removes eight source lines. The complete diagnostic remains owned by the terminal accepted variant until the interpreter transfers it. The residue scan finds no arrival history, duplicate cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax. The actor transition and retained-diagnostic laws were cross-checked against docs/actor-transition-algebra.md and docs/engineering/atomic-actor-retained-core.md. Disposition: pass for these diagnostic item pages; A13 remains open for other ports.

    The creation settlement review found a narrower documentation defect: external caller suites name CreationSettlement, CreationSettlements, and CreationsSettled to retain or return exact child-creation custody, but none appeared as an item in the generated crate-root Rustdoc index. Their public visibility and settlement equations already existed; showing them changes no actor transition. A later read-only downstream inspection found that Bombay's ActionInterpreter explicitly requires InterpretCreations in its CommitActions implementation. That is a real interpreter port and supplies the missing caller evidence to show the trait in Rustdoc as well. The three externally named settlement ports are now listed by Rustdoc: cargo doc -p bombay-behavior --no-deps --locked succeeded with the Nix-provided Rust 1.95 toolchain, and all three crate-root index links and item pages exist. The external generated_creation_custody, custody, and actor caller suites already name these products. Downstream compilation and runtime witnesses remain part of A17; this source inspection does not claim they pass. A second Nix-provided Rustdoc build after exposing InterpretCreations confirmed that all four names have crate-root index links and item pages. The bombay-behavior-doc Nix check passed on signed commit 4cd3b7f, including Rustdoc, the book, and published-document checks.

    The next required runtime method is CreateChild::into_parts. The external creation_initialization_order, creation_settlement_custody, and behavior_generation caller suites consume it to retain the exact child, creator-local ID, and provenance. The real Bombay child host also names it after consuming a RoutedCreation. Its Rust visibility is already public, but #[doc(hidden)] conceals it from an interpreter author reading the API. This is a derived ownership port, not a new actor transition. The focused documentation repair removes that one marker and gives the method an explicit custody description; it adds no type, bound, effect lane, control state, or interpreter capability. The existing external callers are its compile witnesses. The post-edit check is that Rustdoc lists the method on CreateChild and those callers still compile. Post-edit, cargo doc -p bombay-behavior --no-deps --locked generated struct.CreateChild.html with method.into_parts and its custody text. cargo check --locked passed for the external behavior-testkit/tests/creation_initialization_order and behavior/tests/creation_settlement_custody callers; mdbook build docs, formatter, and diff checks passed. The source change is +6/-1 physical lines of documentation only; tests and public type counts are unchanged. Aggregate control states, subordinate alternatives, transition branches, modules, and public spellings are unchanged. The owned child, ID, and kind remain the same complete product; no arrival history, duplicated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax was introduced. The actor transition and creation-custody laws were cross-checked. Disposition: pass for this one documentation port. A13's wider surface review remains open.

    CreationCorrelation<P, Occurrence> is another required, already-public effect prerequisite. The external behavior/tests/action_interpretation and actor interpreter_request_settlement callers name it in ActionItem implementations; its compile-fail example rejects exchange of equal IDs at different occurrences. The derived law is typed correlation to exactly one creation settlement, without granting child-hosting authority. The focused visibility repair removes its Rustdoc hiding marker, retains its private representation and public constructor unchanged, and adds no transition or type. The pre-edit regression is the absence of its item in the generated crate-root Rustdoc index despite those external compile witnesses. The post-edit checks are the Rustdoc index and the occurrence-mismatch doctest. Post-edit Rustdoc has a crate-root link and item page, the focused E0308 compile-fail doctest passed, and cargo check --locked passed for both action_interpretation and interpreter_request_settlement external tests. The source change deletes one hidden annotation; tests, public types, control states, subordinate alternatives, transition branches, modules, and public spellings are unchanged. No history, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax was introduced. The actor transition and occurrence laws were cross-checked. Disposition: pass for this visible prerequisite, with A13 still open for other items.

    CreationId::get is likewise an existing public runtime port concealed in Rustdoc. The actor catalogue derives shutdown and operation correlations from its occurrence-local number; external actor tests also inspect it. Exposing the existing method does not make the number an actor identity or a freshness proof, so its documentation now says that explicitly. The pre-edit symptom was its absence from generated Rustdoc despite external callers. The source edit removes one hidden marker and adds only custody text: zero types, bounds, lanes, states, branches, modules, or public spellings change. The current owned ID remains the sole value. The residue scan is clear for history, repeated cause, false cardinality, nested authority, semantic boolean, and structural syntax. Cross-checks: actor creation law and the exact-correlation consumers. Nix-pinned Rustdoc built CreationId with a visible method.get item, and cargo check -p bombay-behavior-actors --tests --locked passed. Disposition: pass for this documentation-only port; A13 remains open for the wider surface.

    The assignment custody repair narrowed AssignWorker::receipt and AssignWorker::into_parts from public to atomic-module-only after the external consuming settlement passed. Compile-fail fixtures now reject those two old assembly paths with E0624 and reject double settlement with E0382; FIFO/keyed callers, benchmark, and fuzz campaigns use the actual exact-delivery result. The later proxy settlement stage also narrowed its operation ID, request decomposition, and receipt construction after external privacy and closed-control witnesses. The public-surface inventory reflects 81 actor #[doc(hidden)] sites at that checkpoint. The wider port and bound review remains open.

    Pre-edit A13 interpreter-name law: an external interpreter implementing InterpretItem<AssignWorker<Worker, Job>, ...> or InterpretItem<ProxyOperation<Source, Worker, Plan>, ...> must name the corresponding opaque accepted receipt in its return type. The interpreter also names ProxyControl and the immediate proxy result when implementing the concrete ProxyControlAdmission port. These are derived ownership products, not additional actor powers; their fields and receipt constructors stay private. Existing external assignment and proxy caller suites, plus the inspected Bombay interpreter source, prove the naming syntax. Before editing, Nix-pinned cargo doc -p bombay-behavior-actors --no-deps --locked built successfully, but the generated atomic index and item files omitted AssignWorker, AssignmentReceipt, ProxyControl, ProxyOperation, ProxyInputReceipt, and ProxyInputResult because their declarations or grouped re-exports carried #[doc(hidden)]. The focused regression is that these existing names and their custody descriptions appear in Rustdoc while the external caller and compile-fail fixtures keep compiling unchanged. The edit is limited to documentation visibility and regrouping the already public re-exports; it introduces no trait, type, constructor, effect lane, bound, or actor transition. The ownership proof remains the consuming settle methods and the existing static interpreter port. Aggregate states, subordinate alternatives, branches, modules, production public spellings, and current values are unchanged by this visibility repair; there is no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller path to retain. Disposition will be pass only after the item pages, external fixtures, and Nix documentation gate are checked. The focused Rustdoc build now lists all six types in the atomic index and generates their item pages. The actor source has 75 hidden annotation sites, six fewer than the preceding checkpoint. All 13 external fixture test functions passed in debug and optimized profiles. Four compile-fail snapshots changed only the diagnostic's displayed type path; their E0382 and E0599 failures remain the intended ownership and privacy errors. A clean Nix flake check at signed commit b8b9842 passed all eight available macOS checks, including Rustdoc, published-document checks, and 843 optimized Nextest tests. Disposition: pass for these six runtime item pages; A13 remains open for the rest of the surface.

    Pre-edit A13 worker-preparation port law: a trusted worker-source interpreter consumes the owner-emitted PrepareWorkers request, borrows its current source and role, then consumes either an accepted submission or its exact rejection. A multi-role request continues through the owned PendingWorkerPreparation until the complete WorkerPreparation returns. The public methods already express that affine progression; the interpreter must be able to discover those types and methods without guessing hidden Rustdoc paths. This is a derived Bombay ownership port, not a new actor-model operation. External fixed/FIFO actor tests and the inspected Bombay worker_preparation.rs use this exact syntax; no replacement trait or constructor is proposed. Before editing, Nix-pinned Rustdoc omitted the three types from the atomic index. The focused regression is that the existing three types and six progression methods become visible while their constructors, tickets, fields, and owner settlement remain private. This visibility-only batch changes zero control states, subordinate alternatives, transition branches, modules, or Rust public spellings; the exact current source, role, prepared prefix, ticket, and remaining roles retain their one owners. The residue scan is clear for arrival history, duplicated cause, false cardinality, nested transition authority, semantic booleans, and structural caller syntax. Cross-checks are the worker-preparation custody law and normalized atomic pool/supervisor documents. Disposition requires Rustdoc visibility, the external actor suites, and the clean gate. Nix-pinned Rustdoc now lists the three structs in atomic and all six progression methods on their item pages. Actor hidden annotation sites fell from 75 to 66. The external fifo_pool and fixed_supervisor_initialization actor suites passed 91 and 98 tests, respectively. The first clean Nix attempt at signed commit a74b287 stopped during optimized compilation when the machine ran out of disk space; it reported no Rust law failure. After cleaning this repository's generated Cargo target directory, the retry with two concurrent Nix builds passed all ten available macOS checks, including Rustdoc and 843 optimized Nextest tests. Disposition: pass for this documentation port; A13 remains open for the rest of the public surface.

    A13 release disposition: The public-surface inventory now assigns the canonical export groups across all five crates to application, generated-code, test-only, or interpreter ownership. It names lawful implementor roles for all 77 top-level public traits and classifies all 10 remaining core and 22 remaining actor Rustdoc-hidden sites. The still-hidden items are structural products/proofs or the internal HostedInitialization alias; the public requests, receipts, rejections, and custody methods that interpreters must name are visible. The atomic::pool::CustomerDelivery re-export remains hidden only because its canonical atomic page is visible. Caller-facing compile witnesses justify the narrower catalogue bounds, and the Router comparison law explains the one retained identity bound. The redundant DeliveryRouteFor trait was removed after its only external caller passed with DeliveryRoute's associated-address bound in debug and optimized builds; its negative rustdoc fixture failed on the prior API and now passes. The repeatable cold compile comparison and caller diagnostics are recorded in the inventory. No further bound or visibility edit is justified by the current evidence. The complete Nix gate at 7574bcb passed, including Rustdoc and 845 optimized tests. Disposition: pass for the Behavior public-surface review. A17 separately retains the real Bombay runtime witness; closing A13 does not claim that integration.

  • A14 — State the trust scope of initialization capabilities accurately. Confirmed documentation/API mismatch. InitializationTurn says only the lifecycle boundary can issue initialization exactly once. However the public, doc-hidden behavior::initialize(&mut B) can be called repeatedly, and delegate_transition can be called before initialization. Active<B> provides a consuming application path, but it does not restrict those public wrapper ports. They are necessary seams to assess, not proof of universal enforcement. Complete when: specify which operations are trusted wrapper/runtime ports and which invariant the application-facing types actually enforce. Add a legal-user witness for that scope. If stronger enforcement is required, establish its composition law before changing the API; hiding rustdoc is insufficient.

  • A15 — Make coding-rule enforcement agree with the actual repository. Confirmed local-rule deviations. Timer-domain tests invoke mutable accept inside assert!; catalogue models carry readiness decisions as booleans. Many rustdoc fixtures have use sections despite the explicit fully-qualified-snippet rule. Private Operating types in both pools are ambiguous outside their immediate context. These are repository-policy issues; ordinary predicates are not automatically invalid semantic state. Complete when: move transitions outside assertions, express semantic alternatives using domain sums, update snippets and ambiguous domain names, and add focused checks for rules that can be enforced reliably. Keep assertions observational in debug and optimized tests. Audit nested .sends.inner.inner access in testkit/tests/compositions.rs: interpreter structure tests may inspect structure, while ordinary consumer tests must prove syntax that survives an unrelated layer.

  • A16 — Restore developer-facing documentation accuracy. Confirmed drift. The root README installs 0.14 while workspace packages are 0.17.0; four distinct linked documents moved to docs/engineering/. It still names InstallBirth and claims stricter birth-algebra equality than the current role resolver documents. Historical engineering records describe removed templates and tests. Their historical status is useful, but an old “pass” cannot certify current code. Generated-HTML checking does not validate the repository README or compile all book examples. Complete when: root and crate entry points have working links and runnable current examples; current contracts use retained names; historical verdicts clearly identify revisions. Add README link and consumer-snippet checks. Prefer links to one normative law over copied explanations in several docs.

  • A17 — Validate the real downstream interpreter contract. Coverage gap explicitly acknowledged by existing docs. atomic-runtime-settlement.md says Bombay will change to implement the architecture. Local tests include useful scripted interpreters, fabricated established endpoints, and a ProxyRuntimeWitness that returns corruption for every item. Such tests prove static composition and local custody, not a working host, fresh allocation, admission, or retirement transfer. Complete when: a recorded downstream revision runs an end-to-end witness for initial and replacement creation, collisions/exhaustion, initialization stop/rejection, activation, rejection followed by independent effects, closed emitter admission, and parent-to-root residual transfer. Prove that failed replacement establishment never reports restart success. Keep allocation, scheduling, and transport in the interpreter. A read-only inspection found a real EstablishChild implementation in the sibling Bombay checkout, but that checkout has substantial uncommitted work on a separate branch. This branch has not run the required downstream revision/witness, so the scripted testkit trace is not labeled integration evidence. Isolated downstream probe: an unmodified snapshot of the sibling worktree compiled bombay-rs --lib under its Nix-pinned Rust 1.96 toolchain against published behavior crates. With Cargo patches pointing to this branch, compilation stopped at E0046: EntityAdmission<D> has not declared the newer InterpreterRequest::LogicalProtocols projection. Source review found another test-local InitializationRequest implementation with the same omission. The candidate law for a temporary compatibility probe is that both requests use already-owned capabilities and emit no logical actor Delivery, so their emitting actor's logical-host product is empty. This is an inference from the downstream source, not an actor-model guarantee or a successful A17 witness. No change was made to the sibling checkout. In a second isolated copy, those two requests declared the empty logical protocol product and Cargo patched both behavior crates to signed commit 4cd3b7f. bombay-rs --lib then compiled, and five selected downstream targets passed 27 tests: application_children (1), application_terminal_custody (2), entity_application (1), entity_runtime (11), and run_with (12). The selected tests include real application admission, activation failure, passivation, terminal custody, and caller compile fixtures. The snapshot came from the dirty downstream worktree at a7a66e391273; it is not a recorded clean revision, and the temporary projections are not present in that repository. These tests do not prove replacement-establishment failure, every creation collision and exhaustion path, independent sends after rejection, or parent-to-root residual transfer. A17 stays open.

    Address 0.3.0 is now published. In the isolated Bombay worktree codex/interpreter-ownership, Cargo resolves that release while Behavior and Communication remain path-patched research inputs. Bombay's all-target compile passes against this mixed graph. Its current library run passes 174 of 179 tests; five older startup assertions still expect publication after initialization stop or task unwind after a caught pure fold panic. This is neither an immutable integration revision nor an A17 verdict. The original Bombay checkout remains untouched.

P3 — make supporting evidence intentional

  • A18 — Correct benchmark meaning before using performance results. Confirmed benchmark mismatch. protocol_matrix.rs::measure_fsm claims alternating phase changes, but transitions A -> B once and then always stays in B. The base benchmark calls the inherent macro-authored receive method directly, whereas composed cases use activated behaviors. Observing only empty action sizes also weakens confidence that intended work survives optimization. Both benchmark programs report a single elapsed interval. Complete when: preflight traces prove the advertised workload, inputs and resulting state are observable, comparison paths and units are explicit, and repeated measurements report variability. Remove Criterion if these remain custom benchmarks. Measure Machine cloning with a real state and held queue before attempting to change its rollback design.

  • A19 — Preserve truthful error sources and error ownership. Confirmed implementation gap. MachineError, TerminationMonitorError, and TerminationPropagationError manually implement std::error::Error without forwarding an enclosed error as its source. Their fields retain the cause, but standard error-chain consumers cannot reach it. Some public aggregate failures have only their domain sum, so formatting expectations also need an explicit caller contract. Complete when: required display/source contracts use thiserror with truthful source relationships and appropriate narrow bounds; caller tests prove the cause and complete owned rejection survive. Do not reclassify ordinary rejections or settlements as fatal behavior errors.

  • A20 — Maintain a law-to-evidence ledger instead of a test-count claim. Coverage gap. Existing model, fuzz, compile, and mutation evidence is spread across crate-local suites and historical audits. A filename or green suite does not identify which invalid implementation it rejects. Complete when: each law maps to a focused example, a complete trace or independent model, relevant wrapper orders, invalid-use fixture, boundary and ownership cases, and mutation/counterfactual evidence. Mark a layer inapplicable with a reason. Add coverage measurement to locate unexecuted code, but never use a percentage as proof of the law. Keep the workflow's fuzz-target list synchronized with the manifest; it is currently complete. Assignment custody evidence correction: the external delivery fixture previously compared the original Box<str> payload allocation with the address of the delivered Box handle. A temporary equality assertion made both affected tests fail, proving that the old pointer comparison did not identify the payload. The retained fixture now records the delivered str allocation and contents. It verifies that FIFO's current Job: Clone policy sends a distinct copied allocation, while rejection returns the original allocation. Two same-typed requests settle in reverse order and return their own receipts. Debug and optimized external fixture runs pass. This evidence satisfies the Behavior-side return shape of the clarified T02 law: the pool keeps its original job for retry and the worker receives a copy. The runtime close-after-resolution witness remains downstream. The source analysis is in the implementation ledger. Pre-commit host-refusal custody: the external tests/interpreter-contract/tests/startup_host_rejection.rs caller runs a pure initialization with two ordered values whose types do not implement Clone. It then requires HostRejected to return the mutated current child, both original send allocations in order, the untouched staged nested child, the route, creation IDs, kinds, and continuation decision. Debug and optimized fixture tests pass. This proves the Behavior-side return shape; no production host or Address reservation participates, so it does not establish full T11 or close A17.

    Behavior-side law ledger disposition: the focused entries below and the detailed A07/A20 records in this document identify the tested law, an independent trace or model where the law has a sequence, the applicable wrapper and invalid-use boundary, and an actual red baseline, mutant, or isolated counterfactual. A compile-fail fixture is inapplicable to a numeric capacity or stale-event decision that is intentionally decided at runtime; the focused return-value test is its boundary proof. A wrapper-order test is inapplicable to a standalone catalogue policy with no wrapper-owned lane; generic lane composition is tested separately. These are explicit inapplicability reasons, not inferred coverage from a green suite.

    Law clusterFocused and independent evidenceBoundary, composition, and counterfactual
    Core total interpretation and source custodytotal_interpretation, source_settlement_admission, action_interpretation, and the external source_free_custody and source_progression fixtures inspect exact prefixes, residual values, and source admission.Both SendLayer orders, a mixed retirement creation/product and closed source are exercised; the original unconditional Exhausted code failed the focused fixture. External compile denials protect affine settlement authority. Real Driver execution remains A17.
    Fresh creation, occurrences, and startup returncreation, child_occurrence_product, generated creation custody, and external host-refusal/panic fixtures inspect IDs, kinds, routes, current child, error, untouched effects, and complete batch order.Compile-fail and external privacy fixtures reject forged authority; the exact-one caller test was red before into_one. Public publication and Address races remain A17.
    Stable proxy and supervisionproxy, proxy_command_recovery, stable_proxy_shutdown_model, fixed initialization/recovery, and dynamic cancellation/sequence suites check current attempts and ordered joins.The external proxy privacy fixture denies forged receipts and duplicate settlement; A07 activation, fixed, and dynamic mutation slices reject wrong correlations. Runtime restart success remains A17.
    FIFO and keyed workFIFO's independent admission queue and completion tests, keyed binding/assignment models, and the external assignment delivery fixture inspect payload, role, generation, correlation, and complete return.External compile failures deny receipt assembly and double settlement. A07 FIFO and keyed mutations fail the named tests. Actual Communication closure remains A17.
    Lifecycle, time, and workflowExact termination and shutdown models, timing invariants, lease tests, acknowledgement and dependency workflow models compare full event sequences and returned values.Typed observation/shutdown fixtures cover authority; termination, lease, and workflow entries record specific counterfactuals. Numeric time and generation boundaries are runtime rejections, so compile denial is inapplicable.
    Routing, discovery, operations, persistenceIndependent routing, pub-sub, health, cache, readiness, and configuration models compare ordered state and complete Actions after generated operations.Admission, buffer, publication, health, versioned routing, and cache entries record actual mutants or isolated one-line counterfactuals. These standalone policies have no separate wrapper-order law.
    Machine, stash, and state replayfsm_properties, stash_properties, two_buffer, and focused algebra traces check held ownership, replay order, and phase transitions.The machine/stash/cache entry records a wrong phase equality and a no-op drain rejected by focused tests. Static infallibility of stashed inner behavior is the invalid-use boundary.
    Macros and public APIDirect/facade Cargo fixtures, generated creation tests, Rustdoc compile-fail cases, and the external assignment/proxy privacy cases compile through public APIs.Ordinary unrenamed dependencies and facade-first Actors resolution both compile; earlier broken expansions and fixtures failed for the intended compiler diagnostics. Wrapper composition is covered by universal_layers and compositions.
    Testkit and mutation toolingDriver/error properties, independent catalogue models, mutation-gate unit tests, and the pinned Nix coverage measurement exercise the verification machinery itself.A05's missing/failed-run counterfactuals fail the strict gate. Coverage percentages only locate unexecuted branches; the gate requires complete candidate accounting and catches every viable mutant in its selected campaign.

    Disposition: pass for the Behavior-side law-to-evidence ledger. The detailed entries retain their specific limits; this table does not claim that one mutant proves every branch of a catalogue or that a pure model is a real interpreter. Earlier statements that A20 was open describe staged evidence reviews. A17 and the PRD's P5 matrix own the remaining runtime evidence.

Follow-on after the audit checklist

  • Complete the Interpreter ownership and startup PRD against released Behavior crates. The Behavior-owned request, settlement, retained-custody, panic-outcome, caller-migration, documentation, and external-fixture work in P0–P4 is implemented on this branch; the implementation ledger names the exact local witnesses and their limits. T02 was clarified to retain FIFO's existing clone-and-retry policy after its ownership contradiction was proved from source. The original PRD edit remains untouched in the other worktree. Follow its ordered work packages P0–P5 and prove every acceptance trace T01–T24 against the real Address and Bombay interpreters. Include complete rejection and terminal custody, external consumer compilation, release and downstream lock verification, and every required repository gate. Apply its architecture checkpoints and definition of done; the audit checklist does not narrow the PRD's scope. Its optional P6 consolidation follows the blocking contracts only where an independent law proves the deletion. P5's integrated witnesses are required to close A17; the A20 ledger explicitly marks its pure-versus-runtime limits. Those downstream rows remain open after this Behavior release until that proof exists.

Coverage map and what should remain distinct

This table locates the continuation work for every family. Existing evidence is valuable even where A06 or A20 requires a stronger oracle.

AreaExisting evidence inspectedRemaining audit obligation
Core actions, sending, source custodytotal_interpretation, action_interpretation, source admission/custody and settlement testsComplete-product assertions already exist; retain them across A11 and prove hostile source admission
Core addressing, creation, occurrences, event pathscreation/custody tests, child-occurrence product tests, generated creation tests, compile-fail rustdocA01/A14/A17; distinguish logical address, exact endpoint, and creator-local correlation
Machine and stashfsm_properties, error_paths, stash_properties, two_buffer, fuzz sequencesRetain rollback and infallible replay laws; A09/A10/A18
Composition and activationalgebra, universal_layers, init_contract, compositions, owner-scoped deliveryA03/A13/A14; prove consumer inference separately from structural interpretation
Stable proxyproxy, stable_proxy_shutdown_model, operation-settlement tests, shutdown/replacement fuzzA01/A07/A12/A17; preserve return/stop joins and retained affine activation data
Fixed supervisioninitialization, recovery diagnostic, construction and protocol tests; four sequence fuzz targetsA03/A07/A12/A17; preserve ordered role policy, independent outcomes, and complete batch return
Dynamic supervisiondynamic, cancellation and shutdown fuzz targetsA03/A07/A12/A17; preserve key/generation/operation correlation and transferred cancellation
FIFO poolsplit FIFO integration tests, independent admission-queue property, fifo_pool_sequencesA03/A06/A07/A12; prove fairness, retry placement, assignment custody, capacity, and termination independently
Keyed poolbinding, customer, assignment, lifecycle and compile tests; two keyed fuzz targetsA03/A06/A07/A12; preserve binding generations and per-role order separately from FIFO policy
Lifecycle and shutdownshutdown models, heterogeneous shutdown, exact termination model, propagation sequencesA01/A17/A19; distinguish watch recurrence from exact-once monitoring and homogeneous from heterogeneous ownership
Timereceive-timeout model, timing invariants, init/composition tests, timer settlement testsA06/A15; prove exhaustion and stale/duplicate input in both profiles; keep one-shot, periodic, deadline and inactivity policies distinct
Routingcatalogue models, routing/correlation invariants, exact reply testsA06/A07/A11; distinguish sequencer gap closure from explicit watermark release and queue policy from delivery acceptance
Discoveryregistry/topic/pub-sub models, presence fuzz, resolver unit testsAssert snapshot order, stale versions, recipient identity, and complete rejected commands; retain read-only resolver authority
Operations and persistenceconfiguration/readiness/health/cache modelsA06/A13; preserve health tombstones, fixed readiness membership, version conflicts, LRU ownership
Workflowworkflow invariants, barrier/latch tests, catalogue fuzzAssert complete activations and terminal/stale cases; latch, reusable barrier, and dependency workflow have different laws
Macros and published consumersparser permutations, behavior generation, facade fixture workspaceA02/A08; parser success and token text cannot substitute for consumer compilation
Testkit and quality toolingdriver properties, independent models, gate unit tests, Nix/CI definitionsA05–A10/A18/A20

Retain the pure effect boundary, concrete protocol sums/products, owned rejections, sealed structural authority, explicit restart provenance, and deterministic time inputs. A source scan found no dynamic-dispatch/type-erasure escape hatch in the reviewed Rust implementation. Heap allocation, an Arc correlation witness, or a long type is not independently evidence of waste.

Completion method

Work in this order: repair evidence integrity (A04/A05/A08), resolve current contract blockers (A01–A03), strengthen the relevant oracles (A06/A07/A17), then remove proven duplication (A09/A11–A16/A18/A19).

For every retained semantic batch, record the actor-model, derived, or Bombay policy law before editing; write the failing caller or transition regression; identify the existing compositions it reuses or deletes; and complete the AGENTS provenance and aggregate-drift checkpoints. Do not count this audit as those future experiments' approval or evidence. Respect the repository's cumulative surface checkpoints.

Every proposed deletion must answer: what law or consumer needs this code, what breaks if it is removed, and which independent test detects that break? Every proposed abstraction must identify repeated semantics it deletes and prove two real substitutions. Shared test setup may be reduced; independent oracles must not be implemented by calling the production decision logic.

Verification record

A19 pre-edit error-chain law

Classification: Rust caller contract and deliberate Bombay ownership policy. When an aggregate error encloses a causal error, Error::source exposes that exact cause. An ordinary unexpected-report rejection has no causal source and retains its report; a machine failure retains its exact user event. The focused actors/tests/error_sources.rs caller checks all three error types and the owned values. It failed three tests on the previous implementations because every source was None. The existing error sums and fields remain the complete model; the edit changes formatting and source forwarding only. No actor state, effect, interpreter action, wrapper order, or public type shape changes. The aggregate-drift checkpoint is therefore unchanged for control states, subordinate alternatives, branches, modules, and public spellings, with no new arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional user syntax. Disposition: pass for the pre-edit model; source implementation and caller verification follow.

The three existing error shapes now derive thiserror::Error and identify only their enclosed cause as a source. Their manual Debug implementations still avoid a Debug requirement on the owned event or report. The focused caller suite passes all three cases, including None for ordinary unexpected-report rejections and direct inspection of the retained event/report. No source or payload type was added; manual display/error implementations were deleted. Post-edit aggregate states, alternatives, branches, modules, and public spellings remain unchanged. The residue scan and law cross-check remain as recorded before the edit. Disposition: pass.

A08 published consumer and A16 entry-point evidence

The macro consumer test explicitly selects the facade sibling example. A temporary compile_error! appended to that example made the focused gate fail with the deliberate diagnostic; the file was restored. The release-lane package script now assembles all three publishable archives, then extracts their actual contents and runs cargo check on a fresh consumer. Its manifest uses the root README's dependency declarations and patches only the three local archives so unpublished sibling packages resolve. The consumer compiles both #[behavior] and #[pool_worker] from the archived libraries. The archive build and consumer check passed. The Nix package check remains a separate content-list gate because its sandbox has no registry access; it does not claim to build an extracted archive.

The root and three crate READMEs now have current entry points, working local links, and runnable commands. The root consumer dependencies select the packaged versions. Repository link tests cover the READMEs; the core example and macro consumer passed. Historical engineering verdicts now identify the last committed evidence revision (1f20cc4) and point to this current audit. The current root README no longer describes the repaired A03 projection as open. These are documentation and verification changes: no actor control state, effect lane, or public Rust spelling changed. Disposition: pass.

A08 Nix test-runner ownership, before edit

The flake's bombay-behavior-nextest check already runs every workspace unit and integration test in an optimized build; the separate bombay-behavior-doctest check runs the workspace doctests. The bombay-behavior package check also invokes Cargo's test phase, repeating those executable tests and the slow external macro consumer builds. In the committed hash-policy gate, Nextest passed 834/834 cases while the package check separately ran the same crate_resolution cases. The derived gate law is one owner for each test class plus an independent package build: keep Nextest as the workspace executable test gate, keep the doctest check, and make the package derivation build without its duplicate test phase. No source test, target, profile, package artifact, dependency policy, or public API is removed. The focused regression is a full Nix check whose log must show all workspace cases under Nextest and the doctests under their own derivation, while the package derivation completes without another unit/integration test run. Expected files are flake.nix and this audit; production Rust delta and public type delta are both zero.

At signed commit 326f1c2, the clean-worktree nix flake check -L passed all eight active aarch64-darwin checks. Nextest ran 836/836 workspace tests; the doctest derivation passed separately. The package derivation built and installed with doCheck = false and no checkPhase, so it did not repeat the workspace executable suite. The check omitted incompatible systems as usual. No actor state, public spelling, production Rust line, or test case changed. Disposition: pass for the gate ownership repair.

A10 finite-driver contract

drive now explicitly documents that its successful Trace appends send and creation lanes separately and loses turn boundaries. On a later controlled error it returns only the cause, dropping the active behavior and successful prefix actions; the mailbox keeps the suffix after the rejected input. A success-success-error caller test confirms two successful transitions occurred before the error and that one unconsumed event remains. Order-sensitive A01 creation tests use their own per-operation interpreter trace rather than accumulating Trace effects. The focused error-path suite passed five tests. This is a documented limited driver, not a runtime-ordering witness. No actor or testkit state shape, effect lane, public spelling, or transition branch changed. Disposition: pass.

A18 benchmark workload and measurement

The protocol-matrix benchmark now activates the base behavior through the same owned path as its composed cases. A preflight trace checks three exact FSM phases (A -> B -> A -> B), accumulated state 6, and an empty held queue; the timed workload changes phase on every event and observes its final state and phase. The clone measurement uses a 64-value state and 128 held messages before timing, so it measures the actual rollback copy. The FIFO benchmark keeps its complete submit/assignment/settlement/completion cycle and passes the full customer outcome slice to black_box. Both programs now start each sample from a fresh definition and report minimum, median, maximum, and sample count. Matrix rates are transitions per second except clone operations per second; FIFO reports completed cycles per second. The custom benchmark lane no longer depends on Criterion. Three-sample low-iteration preflights ran successfully for both programs; those timings are correctness smoke checks, not performance conclusions. No actor law or state type changed. Disposition: pass.

A11 unused tuple-settlement export, before deletion

Classification: derived ordered-effect product law. A named send product itself owns its declared lane names, settlement shape, left-to-right interpretation, and intact unattempted suffix. The public, doc-hidden settle_in_order function offers only a two-product tuple settlement; it establishes no additional actor capability or independent invariant. A source search across the Behavior workspace and adjacent Bombay/Address repositories found its declaration and two re-exports but no Rust caller. Existing named-product tests and external interpretation callers exercise their own generated traversal, so deleting the dead export changes no transition, effect, or ownership return. Expected production touch: core effects/sending.rs, effects/mod.rs, and lib.rs, about 29 deleted lines, zero new public types, and one removed public function; update the two documents that name it. Core behavior control states, subordinate alternatives, branches, and modules remain unchanged. The future-needed values are each product's named lanes and complete settlements, already retained by its implementation. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax is proposed. Cross-check: actor transition algebra and atomic runtime settlement law. Disposition: pass for this deletion design, pending gates and final measurements.

The unused function and both re-exports are removed. The core production delta is +2/-31/net -29 physical lines, tests +0/-0/net 0, public types +0/-0, and public functions -1; effects/sending.rs is 1,505 → 1,477 lines. Control states, subordinate alternatives, transition branches, and module counts are unchanged, and each named product still owns the same fields and settlement return. The source scan found no remaining Rust call site; the Behavior, actors, and testkit Nextest run passed 808/808 cases, with formatter, book build, and diff checks passing. The residue and law-document cross-checks above still hold. Disposition: pass for the unused-export deletion; A11 remains open for generated logical projection.

A11 pre-edit product-equivalence law

Classification: derived product law and Rust interface cleanup. Buffer's released target deliveries and factual outcomes have exactly the same two named lanes as the existing routing DeliveryOutcomes: deliveries before outcomes for interpretation and append, each lane returned intact on corruption, the same source-custody admission, and the same ordered logical host projection. Neither product owns a Buffer-only invariant; Buffer's queue and overflow policy live in BufferState. The caller-level syntax should therefore be Behavior::Sends = DeliveryOutcomes<TargetSends, ReplySends> for Buffer just as for Sequencer and OrderGate. A focused type assertion in routing/buffer.rs is the pre-edit regression. The existing product, named-product interpretation, tuple source custody, and wrapper composition are reused; the duplicate public BufferSends implementation and its duplicate logical projection will be deleted. No transition, owned effect, interpreter operation, ordering, or error semantics changes.

Aggregate-drift checkpoint: Buffer's control state remains its queue and policy product before and after, with no subordinate state/result alternative or transition branch changes. The exact future-needed values remain the queued owned payloads and reply routes, positive capacity, and overflow policy. The proposed edit deletes a transparent send-product name and its implementations without adding modules, states, branches, public spellings, arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax. The source law is the ordered effect-product equation in actor-transition-algebra.md; the normalized FIFO and routing laws remain distinct and are cross-checked. Disposition: pass for the model, pending the focused test and edit. This does not declare all A11 derivation paths unified.

The focused Buffer caller failed before the edit with E0271: its associated Sends was BufferSends, not the required DeliveryOutcomes. It passed after the edit. The two products had the same public field names and six identical laws (SendEffects, SendsFor, settlement classification/unattempted, source custody, interpretation, and logical-host projection). Buffer now uses the existing routing product; Sequencer, OrderGate, and other routing templates already use it. The former BufferSends spelling and its duplicate projection are gone; there is no compatibility alias. In the affected source, routing/buffer.rs fell from 591 to 498 lines despite the new focused test, and requirements.rs deleted ten net lines. Modules, control states, subordinate alternatives, and transition branches remain unchanged; the one deleted public type is the only public spelling delta. Every surviving state alternative still retains its prior current values. The residue scan and law-document cross-check found no new history, duplicated cause, cardinality assumption, nested authority, semantic boolean, or structural consumer syntax. Disposition: pass for this duplicate deletion. Broader A11 derivation work remains open.

The remaining product paths have different type equations. This inventory is the input to the next A11 design experiment; matching method names alone does not justify merging them.

Product pathProduct and settlement shapeOrdered lanes and shared lawDistinct obligation
Former handwritten DeliveryOutcomes, LeaseSends, PresenceSendsTwo generic fields; settlement reuses the same product with settled field typesEmpty/append, left-before-right interpretation, unattempted suffix on corruption, source custody, classification, and logical projectionTheir public domain field names differ; all three now use the shared private derivation.
Private send_product!, formerly atomic::request_product!One or more generic named fields; settlement reuses the productThe same ordered operations and projection are generated togetherSource custody must preserve every earlier settlement and every unvisited owned field across any arity.
#[behavior] generated sendsGenerated fields may have concrete types; a separate generated settlement struct holds associated settlement typesGenerated lane order, corruption suffix, and source custody use the same transition equationSeparate settlement representation and caller lane methods are part of the generated API; this path currently has no generated logical-host projection.

The named generic products now share the private derivation and retain their public field names and both wrapper orders. The generated product still needs a lawful public projection witness before its distinct settlement shape can share an implementation. This inventory itself changed no product or API.

A11 generated-send projection law, before implementation

Classification: derived typed-composition law. A #[behavior] send product's logical destinations are exactly the ordered, duplicate-preserving append of its declared lane projections. A lane with no logical destination contributes NoBirthProtocols; a nested interpreter-request lane contributes only its declared logical protocols. The caller syntax is <Bootstrap as LogicalHostRequirements>::LogicalHosts, without a handwritten LogicalDeliveryProtocols for BootstrapSends implementation. Existing behavior/tests/behavior_generation.rs has precisely that handwritten implementation, so removing it is the focused pre-edit compile regression. The expected product is FirstDestination followed by SecondDestination. The macro already generates the named send lanes and settlement interpretation; the implementation should reuse each field's LogicalDeliveryProtocols and the existing BirthProtocolProduct::Append. No new runtime operation, transition, wrapper, or host lookup is required. The caller must still compose through existing wrapper projections in either order.

Aggregate-drift checkpoint: the generated behavior's control states, subordinate alternatives, transition branches, production modules, and public type spellings are unchanged. Each lane's current value remains in its existing generated field. The proposed implementation adds one derived trait impl to the existing generated product and deletes the handwritten witness; it stores no history, duplicates no cause, asserts no cardinality, creates no nested transition authority or semantic boolean, and exposes no positional consumer path. The law is cross-checked with actor-transition-algebra.md and the normalized logical-host contracts in this audit. Disposition: pass for the pre-edit model, pending the focused failing regression.

Removing the handwritten BootstrapSends projection produced E0277 in the Nix-pinned behavior_generation caller: both BootstrapSends and a second generated product with a request lane and repeated delivery destination lack LogicalDeliveryProtocols. An unconditional generated impl using the field projections then failed E0446 for existing private interpreter-request types. That candidate was removed, the test fixture restored, and the experiment recorded in the root DEAD_ENDS.md. A11 remains open; a public interface law must be established before another generated projection edit. A later public wrapper probe avoided E0446 but lost the concrete structural product needed for recursive host traversal. Its reopen record is also in DEAD_ENDS.md; no generated projection was retained. The existing behavior_generation caller now uses a direct PhantomData type check in place of a one-implementation Same trait to keep the exact structural product requirement visible with less test machinery. All 18 cases in that test binary passed under the Nix-pinned toolchain.

A11 named generic product derivation, before implementation

Classification: derived ordered-product law and private implementation consolidation. LeaseSends<OutcomeSends, Schedules> and PresenceSends<ReplySends, Schedules> each own two named generic lanes. For both, empty and append act lane by lane; interpretation visits the first lane before the second, preserves the unattempted suffix on corruption, and continues to the second lane after lawful rejection. Source admission visits in the same order and returns the complete named product. Settlement status combines both lanes, and logical-host projection appends their protocol occurrences in order. The distinct public field names remain part of the contract. This is the same law already derived by the private atomic request_product! macro for generic named lanes. Moving that existing derivation to the actor-crate root and giving it a domain-general send-product name can delete the duplicate implementations; it adds no public framework.

Focused characterization before production edits passed in the Nix-pinned toolchain: requirements::tests::lease_and_presence_products_keep_both_wrapper_orders proves both logical orders through SendLayer; total_interpretation checks Lease's corrupt suffix and Presence's rejection followed by its independent schedule lane. These tests pass on the prior implementation because this stage removes duplication without changing the observable law. The existing four atomic request products and the core ordered settlement and source-custody products remain the lower-order witnesses. The expected design-stage files are the private derivation module, its four atomic import sites, the actor crate root, Lease, Presence, their two projection impls in requirements.rs, and the focused tests. The expected production delta is roughly 200 fewer lines, with zero new or removed public types; later product migration is a separate measured stage.

Aggregate-drift checkpoint: Lease and Presence control states, subordinate alternatives, transition branches, modules by count, and public spellings remain unchanged. The exact current values are Lease's owned outcomes and schedule requests and Presence's owned replies and schedule requests. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax is introduced. The ordered send-product equation in actor-transition-algebra.md and the normalized timing and presence contracts are cross-checked. Disposition: pass for the pre-edit model and both focused caller witnesses.

The design stage moved the existing 273-line private macro from atomic requests to the actor-crate send-product owner, changed its private name, and retained field rustdoc. Lease and Presence now invoke it with their original public field names. Their handwritten SendEffects, SendsFor, settlement, source-custody, interpretation, and separately maintained logical-projection impls were deleted. Both wrapper-order projections passed, all five focused total-interpretation cases passed, and the actor crate's 158 unit tests passed under nix develop. The retained production representation is 196 physical lines smaller; focused tests add 56 lines, yielding 169 fewer actor src lines including its new unit test. Public types and spellings, modules by count, aggregate states, subordinate alternatives, and transition branches are unchanged. Every surviving product field still owns its prior value. The residue scan and law-document cross-check remain as recorded above. Disposition: pass for the design stage. Other generic products are a separate mechanical migration; the distinct proc-macro-generated settlement shape remains an open A11 design question.

The measured mechanical stage applies only the proven syntax to DeliveryOutcomes, WorkQueueSends, BreakerSends, TerminalPropagationSends, and ProxyEffects, and removes their matching separate projection impls. Each has generic named fields, the same ordered interpretation/source-custody/settlement equation, and an existing real consumer. Expected production delta is roughly 800 fewer lines, with zero new or removed public types. No new effect lane, bound, state, or fixture is authorized by this migration; a mismatch reopens the derivation instead of adding a one-off branch.

The mechanical stage now uses the shared derivation at those five sites and deletes their former implementations. ProxyEffects retains all seven public field names and their declared order while losing its nested tuple source plumbing. The actor src tree changed by +111/-1,104 physical lines, net -993 including the focused unit test; the production representation alone is about 1,020 lines smaller. No public type was added or removed. The actor all-target Cargo check, formatter, 812 workspace Nextest cases, and current workspace coverage run passed under the Nix toolchain. The full 21-check Nix flake gate also passed from a clean worktree at signed commit 65caa65.

Post-migration aggregate-drift checkpoint: the affected routing, timing, discovery, lifecycle, and stable-proxy control states, subordinate result alternatives, and transition branches are identical before and after; no aggregate transition function changed. The current values in every surviving send alternative are the same owned effect lanes, including all seven stable proxy lanes. Modules remain constant by count because the derivation module moved from atomic/ to the actor root. Public spellings remain constant. The residue scan found no new arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional consumer syntax. The ordered product law in actor-transition-algebra.md and the normalized atomic, routing, timing, discovery, and lifecycle contracts were cross-checked. Disposition: pass for the retained representation.

A11 named-send equation inventory

The two current general derivations preserve the same named field order and the same complete settlement alternatives, but they have different authoring inputs. This is a pre-design comparison, not approval for a shared public product framework.

Equationsend_product! in actors#[behavior] proc macro
Authored productA generic named struct with semantic fields.A behavior declaration generates a named sends struct, a distinct settlement struct, lane selectors, and fluent action methods.
Empty and appendDelegates to each field in declaration order.Delegates to each field in declaration order.
InterpretationTraverses fields in declaration order; corruption preserves the committed prefix and makes the untouched suffix unattempted.The same ordered traversal and corrupt suffix equation.
Settlement statusCombines every named field.Combines every generated settlement field.
Source custodyOffers each field in order; admission or closure retains the complete remaining product.The same ordered offer and remaining-product equation.
Event-lane routingComposes the fields' SendsFor<Event> proofs; authored code selects a concrete field.Composes the fields' SendsFor<Event> proofs and generates SendInput selectors and fluent methods.
Logical hostsAppends every field's LogicalDeliveryProtocols in interpretation order.No generated LogicalDeliveryProtocols implementation is present. A lawful addition must distinguish logical deliveries from exact and interpreter-request lanes.

ReplyDeliveries has a logical and an established route with distinct target laws; HeterogeneousShutdownSends has its own finite target shape. Their manual projections in requirements.rs are therefore evidence of semantic exceptions, not merely missed macro invocations. The next A11 hypothesis must prove the logical-host equation through two unrelated proc-macro behaviors and both wrapper orders before it can subsume either derivation. The aggregate drift checkpoint for this inventory has no retained production change: control states, subordinate alternatives, branches, production lines, modules, and public spellings are unchanged; no new history, cause, cardinality, transition authority, semantic boolean, or positional consumer syntax is introduced. Disposition: pass for the evidence record only.

The next focused A11 law is a derived logical-host projection: a generated named send product contributes each field's LogicalDeliveryProtocols in its declared order, including duplicates, while exact delivery and interpreter request fields contribute their existing empty projection. The user-level syntax is a LogicalHostRequirements bound on two unrelated generated behaviors and LogicalDeliveryProtocols bounds on both SendLayer orders; the expected type product spells the actual protocol order. Before changing the proc macro, caller tests in behavior_attribute.rs and compositions.rs must fail solely because the generated named sends lack this trait. Existing field projections, BirthProtocolProductAppend, and wrapper composition are the lower-order laws. No actor state, effect lane, transition, generic parameter, runtime port, or policy is added. Pre-edit aggregate drift: control states, subordinate alternatives, transition branches, production lines, modules, and public spellings stay unchanged until the focused witness fails; the generated product retains only its authored fields. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax is proposed. Cross-checks: actor-transition-algebra.md, behavior-layer-laws.md, and normalized atomic documents. Disposition: pass for the proposed projection model, pending the red caller witness.

The two caller tests failed before production with only E0277: generated PrinterSends and GeneratedBaseSends lacked LogicalDeliveryProtocols. Printer's direct logical-host bound and both SendLayer orders failed for that missing trait; GeneratedBase failed for the same reason. The first draft of the wrapper type assertion expected the outer lane before the inner lane and produced an unrelated E0271; it was corrected to the existing inner-before-outer law in SendLayer before this red result was accepted. A 24-line generated-impl candidate then reopened the design. It conflicted with an existing handwritten BootstrapSends impl and leaked private protocol/request types from public generated products (E0446). The candidate and focused test edits were removed; the exact falsifier and post-experiment drift checkpoint are in DEAD_ENDS.md. The missing projection remains open and requires an explicit visibility/ownership model before code.

Next A11 visibility hypothesis, before implementation: a generated named send product is part of a public actor's interface only when that actor exports it. The #[behavior] attribute is applied to an impl, so it cannot inspect the actor declaration's visibility. The current unconditional pub product makes private actors' private request and destination types leak through the generated LogicalDeliveryProtocols::Protocols associated type. A Rust 1.95 scratch compile confirmed that a private product may implement this public trait with a private projected protocol, while a public product triggers E0446 for the same private protocol. The candidate syntax keeps sends = { ... } module-private and permits the ordinary Rust visibility spelling sends = pub { ... } when a public actor deliberately exports the product. Generated lane selectors, settlement product, and fluent trait must have the same visibility as the named product; no consumer supplies a no-op route, marker, or policy. The generated projection appends every field's existing LogicalDeliveryProtocols::Protocols in declared order, retaining duplicates and the empty projections of exact and request lanes. Private Bootstrap, Printer, and GeneratedBase are real callers; a public actor with public recipient protocol will prove the exported form. The prior two-behavior E0277 regressions and both SendLayer orders are the focused red witnesses, supplemented by a red parser witness for sends = pub { ... }. The existing BirthProtocolProduct::Append, field projections, product settlement, and wrapper laws are the lower-order contracts. No actor control state, event, effect lane, interpreter operation, or policy is authorized to change. Pre-edit drift: product fields and order, actor states, transition branches, production modules, and public actor spellings remain fixed; the generated product's public exposure is the one intentional interface change for private actors. The values needed later are each declared send lane's logical-host protocol product and its exact settlement custody. There is no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax in the proposed model. Cross-checks are the actor transition algebra, behavior layer law, recursive host consumer in logical_host_requirements, and normalized atomic docs. Disposition: pass for the hypothesis only, pending focused red witnesses and a full generated-product visibility inventory.

The focused pre-edit callers now fail in the intended places. compositions reports three E0277 diagnostics because GeneratedBaseSends lacks LogicalDeliveryProtocols: one direct owner and each SendLayer order. behavior_attribute reports the same three E0277 diagnostics for PrinterSends; its deliberately public actor is rejected at sends = pub by the old parser, so the later missing Behavior diagnostic is a consequence of that parse failure. No route, birth, or settlement mismatch appears in the red logs. The public actor emits a real reply, and neither private caller supplies an inert policy or placeholder.

The design-stage candidate now derives LogicalDeliveryProtocols from the named fields and makes generated send products and their companions private by default, with an explicit Rust pub form for an exported actor product. The private BootstrapSends handwritten projection was deleted. The two focused testkit suites passed 6 and 11 tests, including their exact direct and both-order host products; core generated-product and source-admission suites passed 19 and 6 tests. The duplicate-lane test retains two occurrences of the same destination after an empty interpreter-request lane, while a request-only product projects the empty host product. An external fixture successfully names both the public send and settlement products and checks its exact logical host type. All workspace targets passed cargo check under the Nix toolchain. The macro unit suite passed 6 tests. The full Nix gate for this candidate remains pending.

Post-design aggregate-drift checkpoint: actor control states, subordinate state alternatives, transition branches, send field order, settlement alternatives, and runtime ports are unchanged. The macro parser still has the same Existing/Generated send alternatives; Generated now retains the explicit Rust visibility needed for its public interface. The macro source grew from 1,499 to 1,534 physical lines, including the visibility parser and one generated logical-host implementation template. The eight-line handwritten BootstrapSends projection disappeared; production module count is unchanged. Existing generated product names are retained, but products for private actors cease to be unnecessarily public, and the new exported form is public by declaration. The surviving values are each named send lane, its exact ordered settlement, and its statically projected logical-host protocols. The residue scan finds no arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural consumer syntax. The actor transition, wrapper-order, and recursive host contracts were cross-checked. Disposition: pass for this focused projection and visibility stage, pending its full gate. The wider A11 one-implementation derivation remains open.

Clean 24fe931 Nix gate: all ten active aarch64-darwin checks passed, including the optimized Nextest campaign (841/841). The four macro fixture checks took about three minutes each under the shared fixture lock; all passed.

Next A11 consolidation hypothesis, before implementation: an authored generic named send product and a #[behavior] generated named product have the same field-order, empty/append, logical-host, interpretation, source-custody, and settlement-status equations. Their Rust settlement representations differ: the authored product is generic over each lane and reuses its own struct with settled lane parameters, while the behavior attribute generates a separate nominal settlement struct for concrete authored lane types. A shared procedural generator should own the traversal equations, with that representation difference explicit. The caller syntax for an authored product is a normal named generic struct with a SendProduct derive; its public fields, generic parameters, settlement associated type, and ordered Actions remain identical. The first focused regression will use a real two-lane effect fixture and fail on the old code because this derive does not exist; it must then prove accepted, retained, closed, and corrupt suffix custody. Two unrelated existing products, DeliveryOutcomes and LeaseSends, and both SendLayer orders must pass before any catalogue migration. The lower-order contracts are the current send_product! equations, the generated product just proved above, ActionItem settlement products, and the recursive logical-host proof. No new actor state, event, effect lane, runtime port, or no-op caller input is authorized. Pre-edit aggregate drift: all actor control sums, subordinate alternatives, transition branches, product fields, and public spellings remain fixed. The candidate may add one proc-macro entry point while deleting the 273-line declarative derivation after proof; source-line reduction is diagnostic, not acceptance. Each lane's owned settlement and declared order remain the only future-needed values. The residue scan finds no proposed arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional caller syntax. Cross-checks: actor transition algebra, A11 equation table, source settlement law, wrapper law, and normalized routing/timing contracts. Disposition: pass for the hypothesis only; implementation must reopen if a third representation or caller placeholder is required.

The pre-edit SourceAdmissionSends<ProxySends, AssignmentSends> caller now uses the proposed derive on two real source-action lanes. It checks the exact generic settlement type; empty/append; accepted first admission; closed second admission with complete residual custody; corrupt first result and unattempted second suffix; and rejected-result retention. On the old code, its first diagnostic is E0433 for the absent behavior_macros::SendProduct; the remaining seven diagnostics are the missing trait implementations that this derive is meant to produce. No unrelated interpreter or route mismatch appears in the red log.

Retained A11 derivation batch: SendProduct now derives the named generic product contract for authored lanes. The two unrelated actor products DeliveryOutcomes and LeaseSends passed the 167 actor unit tests in debug and optimized builds. The source-custody fixture passed eight tests, including both orders around SendLayer; the generated-product fixture passed nineteen. All eleven former send_product! declarations compile through the derive, and workspace --all-targets tests passed. The 273-line declarative macro and its module were deleted. One procedural settlement generator now owns classification and ordered source custody for both authored and generated products; the interpreter traversal is shared as well. The remaining duplicate effect-product trait generation between the two procedural paths must be consolidated before A11 closes.

Aggregate-drift checkpoint for this retained derivation batch: actor control states, subordinate alternatives, transition branches, effect lanes, and public product spellings are unchanged (zero added or removed). Eleven macro invocations became eleven ordinary named structs with one derive each; one actor source module was removed. Every surviving field owns the same current lane value needed for ordered interpretation and exact settlement return. The residue scan found no new arrival-history state, duplicated cause, false cardinality, nested transition authority, semantic boolean, or positional consumer syntax. Cross-checks: the actor transition algebra, A11 equation table, source-settlement law, both wrapper orders, routing and timing contracts. Disposition: pass for the already-proven representation migration; the remaining common trait generation is still open.

Follow-up A11 consolidation: named_send_contract now generates all five send-product traits for both authored and #[behavior] products, while named_settlement_contract generates their classification and source custody. Only their truthful settlement representations and generated fluent lanes remain separate. This removes another 100 net production lines from the macro crate. The focused generated and authored tests (19 and 8) and workspace --all-targets tests passed after the consolidation. The first clean Nix gate for the preceding migration commit reached the documentation checker, which found six consuming calls inside new assertions. The test moved those calls before the assertions; its focused tests and check_assertion_effects.py now pass. A clean gate on the corrected consolidation is pending.

Aggregate-drift checkpoint for consolidation: actor control sums, subordinate alternatives, transition branches, product fields, modules, and public spellings all remain unchanged (zero delta). The macro crate replaces two copies of the same five trait equations with one generator; no current actor value is added or removed. The residue scan remains clear for arrival history, repeated causes, false cardinality, nested transition authority, semantic booleans, and structural caller syntax. Cross-checks: actor transition law, A11 equations, source-custody law, generated behavior contract, both wrapper orders, normalized routing and timing documents. Disposition: pass; the clean Nix gate passed all ten checks with 843/843 optimized tests.

A12/A13 least-loaded membership owner, before edit

Classification: deliberate Bombay routing policy and derived Rust ownership law. Router owns the ordered, duplicate-free member list. LeastLoaded needs exactly one current LoadEvidence per member position, not a second copy of each recipient. On add it appends Unknown; on removal it deletes that position; observations find the member in the Router list and update only the aligned evidence; selection uses the first minimum observed load. An unknown, stale, or conflicting observation still returns the exact request. The caller syntax is Router<A, Recipient<P>, LeastLoaded> and router.load_evidence(&recipient); it borrows for observation and exposes neither an index nor a route parameter on the policy's stored state. Two different protocol routes can use the same policy type. The existing independent least-loaded trace is the pure transition oracle; the external protocol_bounds compile witness must first fail solely on the old required generic argument.

Before-edit aggregate control is one Router membership list, with LeastLoaded holding a parallel list of recipient/evidence pairs. After the candidate, Router remains the only member identity owner and the policy holds an aligned evidence list. The subordinate sum remains Unknown or Observed (version, load); its current version/load are needed for every later selection and stale/conflict decision. Neither the actor's control states nor its effects, errors, interpreter path, transition branches, or module count change. Expected files: routing/router.rs, the external protocol caller, the routing model, and this audit; expected production delta is negative and no public type is added. The public policy loses one generic parameter and its direct recipient lookup; Router gains one semantic evidence lookup. The current Router::new and membership transitions are the only legitimate policy-hook callers; direct policy use with an unrelated member slice must return typed unknown evidence, not index-panic. The residue scan finds no arrival history, duplicated cause, false cardinality, nested authority, semantic boolean, or structural user syntax. Cross-checks are the actor transition algebra and normalized routing law. Disposition: pass for the model, pending the focused red compile witness and implementation.

Post-edit checkpoint: protocol_bounds failed before the production edit with only the two expected E0107 diagnostics for LeastLoaded's unwanted route parameter, then compiled with Router<MailAddr, Recipient<Destination>, LeastLoaded>. The independent 384-case least-loaded trace passed in debug and optimized builds. All eight focused router unit tests passed, including the exact owned observation returned when a direct policy caller supplies a member slice without matching policy evidence. mdbook build docs passed.

The Router control state remains one ordered, duplicate-free membership list; the four message alternatives and three Router error alternatives remain four and three. Policy evidence remains the same two-alternative sum, Unknown or Observed(version, load), and its three typed rejection alternatives remain three. There is no new transition authority, module, effect, or interpreter path. The production portion of routing/router.rs fell from 879 to 863 physical lines; one private recipient/evidence product disappeared. The public policy loses its route parameter and direct identity lookup, while the Router gains the recipient-based evidence lookup. Router owns current member identity and order; the aligned policy evidence owns the current load and version needed for selection and stale/conflict decisions. Rechecking the actor transition algebra and normalized routing laws found no arrival-history state, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional syntax exposed to callers. Disposition: pass.

A12/A13 hash-token membership owner, before edit

Classification: deliberate Bombay hash-routing policy and derived Rust ownership law. The Router already owns its ordered, duplicate-free recipient list. Both hash policies need exactly one current Unknown or Observed(version, token) evidence value at each member position; neither needs a second owned copy of each recipient. Add appends Unknown, removal deletes the same position, observation resolves the recipient in the Router snapshot and updates only that position, and selection considers the observed tokens in membership order. Unknown, stale, and conflicting observations must return their exact owned request. The caller syntax is ConsistentHash<K> or RendezvousHash<K> inside Router<A, Route, _>, with router.member_token_evidence(&recipient) for current evidence. One policy type must work with different eligible route types for the same key.

The focused pre-edit caller regression is the external keyed-routing test's Router<..., RendezvousHash<u64>> and a corresponding ConsistentHash<u64> type witness; they must fail only because the old policy demands an unrelated route parameter. Existing rendezvous membership/permutation properties and the consistent-hash removal test are the independent transition witnesses. The direct policy boundary must return UnknownRecipient with the complete observation when its passed member slice has no aligned evidence, without an index panic. Existing RoutingStrategy hooks, MemberTokenObservation, and the two concrete selectors are reused; no runtime or effect product changes.

Aggregate-drift precheck: Router retains one ordered member list before and after. HashMembership changes from a second list of recipient/evidence products to the aligned evidence list; its Unknown and Observed alternatives stay two, and their current version/token remain necessary for later selection and stale/conflict decisions. Router's four messages and three errors, the hash policies' three rejection alternatives, all actor control states, transition alternatives, modules, and interpreter paths stay the same. Expected edit files are routing/router.rs, the keyed routing caller, this audit, and any focused direct-policy regression. Expected production delta is negative, with one private product and two public route parameters removed, no public type added, and one Router evidence lookup added. The residue scan finds no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax. Cross-checks are the actor transition algebra and normalized routing law. Disposition: pass for the proposed model, pending the red witness and implementation.

Post-edit checkpoint: the external keyed-routing caller failed on the old policy shape with exactly two E0107 diagnostics, one for each unwanted route parameter. The new caller syntax compiles. The nine focused router unit tests pass, including complete typed return of an untracked observation from both hash policies. All nine routing invariant tests pass in debug and optimized builds; their rendezvous trace includes membership edits, evidence versions, selection, and token-order permutation. mdbook build docs passes. The full workspace gate for this batch is pending.

The Router control state and its four commands/three errors are unchanged. The policy evidence still has two alternatives and the hash rejection still has three. The production portion of routing/router.rs fell from 863 to 850 physical lines, despite adding the recipient-based Router lookup; the private HashMember<Route> product and the second recipient list disappeared. Both public policies lost only their route parameter and direct recipient lookup; their key parameter remains because two key types and their hash functions are valid substitutions. No new type, trait, module, effect, actor transition branch, or interpreter path was introduced. Router retains member identity and order; the policy retains only current version/token evidence. The shared private member-index operation serves all three evidence lookups. Rechecking the actor transition algebra and normalized routing law found no arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax. Disposition: pass for this representation, subject to the pending full gate.

A12/A13 router observation rejection custody, before edit

Classification: derived affine Rust ownership law; neither Agha's transition effects nor hash-routing policy prescribes a Rust error representation. A policy consumes one typed observation. If it cannot accept that observation, it must return the same owned observation with one concrete reason, and Router must retain exactly that returned value while discarding the mutated policy candidate. Acceptance commits the candidate and returns empty continuing Actions. There is no need for an observation to implement Clone: it can own a move-only payload. The current trait returns only Self::Error; Router therefore clones the input first, and the built-in LeastLoadedError<Route> and HashPolicyError<Route> carry a second copy of it. One semantic cause has two owners and every runnable policy observation inherits a cloning bound.

The caller syntax is a running Router<MailAddr, Recipient<Destination>, ObservedSelection> accepting the existing non-cloneable AcceptedPayloads(Vec<u8>), followed by a rejecting move-only observation whose exact allocation returns through RouterError::Policy. The external protocol_bounds caller must first fail only because the old Router behavior requires R::Observation: Clone. A focused pure transition test will then prove pointer identity, complete rejected ownership, policy-state rollback, and one successful commit. The public policy seam should return one named observation/reason product; the aggregate RouterError::Policy remains the sole actor error owner. Once the observation moves to that product, LeastLoadedError and HashPolicyError have the same three payload-free reason alternatives and ownership equation. One shared MemberEvidenceError should replace both, without a compatibility alias. RoundRobin remains statically unable to observe. Existing RoutingStrategy hooks, typed RouterMessage, policy candidate rollback, delivery effects, and interpreter path are reused. No policy needs a no-op placeholder.

Pre-edit drift checkpoint: Router retains one ordered member list and the same four message and three actor-error alternatives. Least-loaded evidence remains Unknown/Observed(version, load); hash evidence remains Unknown/Observed(version, token). The shared policy reason retains the same three alternatives without duplicating the observation. The proposed public surface adds one named rejection product and one shared reason sum, removes two policy-specific reason types and the observation-clone bound from Router's transition; no new actor state, effect, interpreter capability, module, or transition branch is authorized. Expected production delta is negative after removing redundant payloads, manual Debug implementations, and cloning. Current membership/evidence and the actual rejected observation are exactly the values needed for later decisions and ownership return. The residue scan finds no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax in the proposed model. Cross-checks are actor-transition-algebra.md, the routing law in atomic-actor-other-templates.md, and existing wrapper composition tests. Disposition: pass for the proposed model, pending red caller and pure transition witnesses.

The external caller now constructs and advances the existing ObservedSelection with non-cloneable AcceptedPayloads. Before any production edit, its explicit Behavior witness fails with E0277 naming only the missing AcceptedPayloads: Clone bound; the subsequent initialize E0599 is the same unmet Behavior obligation. There is no unrelated route, send, or address diagnostic. The acceptance action and committed policy state are asserted in the caller test. Before production code, the rejecting move-only custody regression failed because the named rejection product did not exist and the Router still required Observation: Clone. After the interface and built-in policy changes, all 11 focused router unit tests and all four external protocol-bound tests pass. The pure rejection test checks the returned Box allocation address, complete reason, discarded candidate mutation, subsequent accepted observation, empty observation effects, and the resulting delivery. LeastLoaded and the two hash policies use the same rejection product; RoundRobin's uninhabited observation remains unchanged.

Post-design drift checkpoint: Router still has one control state, four messages, three actor-error alternatives, and the same four transition arms. Least-loaded and hash evidence each retain Unknown/Observed; their two three-alternative reason sums became one three-alternative sum. The production portion of routing/router.rs grew from 850 to 866 physical lines because each rejection now explicitly returns its owned observation and reason; two manual Debug implementations and the Router observation clone disappeared. The two removed public error names were replaced by the shared reason and named ownership product, so the public type count is unchanged. Modules, effect lanes, and interpreter capabilities are unchanged. The current member evidence is the only policy-local value needed for the next selection; the returned observation is needed only for the exact rejection. The residue scan finds no arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax. The actor transition, routing, and wrapper composition laws were cross-checked. Disposition: pass for the design stage; testkit migration and the full gate are separate follow-up work.

Mechanical caller migration at f936dc8 changed only the routing invariant test's three rejection patterns to inspect the one returned observation and the shared reason. Its generic route witness no longer asks for an unrelated observation-cloning bound. All 10 focused routing invariant tests pass in both Nix-pinned debug and optimized builds. This stage adds no production type, transition, branch, module, or policy.

The clean-worktree nix flake check -L at signed commit 26d2261 passed all eight active aarch64-darwin checks, including optimized Nextest with 838/838 passing cases, doctests, Clippy, Rustdoc, documentation links, formatting, package build, and deny. This closes the gate for the router observation-custody design and its mechanical test migration; A12/A13 retain their broader audits.

A13 pre-edit base-projection law

Classification: derived, read-only composition law. BehaviorBase on an unwrapped catalogue actor returns &Self; it neither constructs nor advances that actor. Naming this projection must therefore require only the bounds that make the actor type well formed. Clone and Eq on a command key or payload belong to construction or transition when those operations actually copy or compare values. The caller syntax is a BehaviorBase<Base = Self> bound on Acknowledgements, Resolver, Configuration, and Readiness with opaque non-Clone, non-Eq domain values. Its observable product is the same shared reference, with no action or state transition. The focused external protocol_bounds witness must fail only because the current base-projection impls carry those operation bounds. Existing Protocol witnesses and the runtime transition tests are the lower-order contracts; no new effect lane, interpreter operation, wrapper, or actor state is proposed. Before-edit control states, subordinate alternatives, transition branches, and public spellings are unchanged. The current values in each actor remain its exact records, bindings, versioned configuration, or dependency observations. The residue scan finds no proposed arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional caller syntax. Cross-check: BehaviorBase in transition.rs, the actor transition algebra, and the normalized catalogue contracts. Disposition: pass for the proposed law. The external witness failed before production edits with ten E0277 diagnostics, all from the four named BehaviorBase impls demanding Clone or Eq for opaque Key/Value. There was no route, protocol, or associated-type failure. This is one repeated interface-bound error, so the edit is limited to removing those operation bounds from the four read-only impls.

The same derived read-only law applies to Machine, Topic, PubSub, Presence, Lease, Barrier, Workflow, and OrderGate. Their base method also returns &Self, while the current impls demand copying, equality, or ordering used by other operations. The second focused caller stage names BehaviorBase<Base = Self> for the already opaque payload/key/phase types, including an OrderGate whose key has no Ord. It must fail before editing these eight impls solely on their operation bounds. The existing actor type/route bounds stay in place. No state or action changes; the ownership, residue, and law cross-check above apply to this extension too.

The initial caller draft reused protocol-only topic aliases whose Subscription deliberately is not a delivery route; that unrelated error was corrected before accepting the red result. With lawful concrete routes, the second stage failed with sixteen E0277 diagnostics, all for the eight impls' copying, equality, or ordering bounds. No route error remained.

After both stages, the focused external caller passes all three cases and workspace Nextest passes 827/827. The twelve production files changed by +0/-16 physical lines (1,517 → 1,501); the external caller gained one compile witness with twelve concrete substitutions. Aggregate control sums, subordinate alternatives, transition branches, modules, public spellings, stored values, effect lanes, and interpreter operations are unchanged before and after. Every surviving state alternative still owns the same current value. The residue scan found no arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional caller syntax. The BehaviorBase contract and catalogue laws remain the cross-check. Disposition: pass for this bound-only batch; A13 remains open for other public ports and protocol bounds. The complete nix flake check -L passed all eight declared local checks at signed commit 790d194, including the optimized workspace Nextest and release-test lanes. Later routing bound and test-only batches passed their focused Nix tests; they still need the final flake run together.

A13 pre-edit routing identity law

Classification: derived, typed-protocol identity law. Deduplicator and OrderGate command types name a key and two concrete delivery routes; identifying those messages neither compares nor copies the key. The Deduplicator base projection also only borrows Self. The caller syntax is an external Protocol<Msg = ...> bound for both actors and a BehaviorBase<Base = Self> bound for Deduplicator, with an opaque key that implements no Clone, Eq, or Ord. The complete observable product is the same associated message type or shared reference, without a transition. The focused protocol caller must fail on the old impl-only key bounds before production changes. Existing route and actor type bounds, transition tests, and the preceding base-projection witness are lower-order contracts. The candidate changes no event, effect, state, runtime port, wrapper, or public spelling. Baseline control sums, subordinate alternatives, transition branches, and modules remain fixed; the deduplicator retains its FIFO key window and the gate its watermark and held map. The residue scan finds no proposed history, duplicate cause, false cardinality, nested authority, semantic boolean, or positional caller syntax. Cross-check: actor transition algebra and the routing catalogue contract. Disposition: pass for the pre-edit law. The external caller failed before production with six E0277 diagnostics: Clone/Eq from the deduplicator's two impls and Clone/Ord from the order gate's protocol impl. No route or message-shape error occurred.

The focused external caller and the 827-case workspace Nextest suite pass after removing those three impl-level lines. These two production modules changed +0/-3 physical lines (752 → 749); test syntax adds two protocol substitutions and one base-projection substitution. Control states, subordinate alternatives, transition branches, modules, public spellings, effect lanes, interpreter operations, and retained values are unchanged. The deduplicator still owns its FIFO key window; the order gate still owns its watermark and held map. The residue scan and law cross-check above remain clear. Disposition: pass for this interface-only batch; A13 remains open.

A13 pre-edit priority-protocol law

Classification: derived, typed-protocol identity law. A priority-queue command carries an application priority as owned data; only construction and release ordering require Ord. BinaryHeap<Entry<T, P>> can be stored before Entry<T, P>: Ord is available; the ordering proof is needed when operations use the heap. The external syntax is a Protocol<Msg = PriorityQueueMessage<...>> and BehaviorBase<Base = Self> bound with an opaque priority type. Neither syntax constructs or transitions the queue. The prior design is expected to fail this caller solely at the struct's P: Ord bound. The existing priority selection/FIFO trace and construction tests witness the lower-order operation contract. The candidate removes the bound from the aggregate declaration and the two read-only impls, retaining it on construction and Behavior. It adds no new state, effect, policy, interpreter operation, or public spelling. Baseline control phases remain Active and Exhausted; the current values remain capacity, next token, and owned heap entries. Transition branches, subordinate alternatives, modules, and wrapper products are unchanged. The residue scan finds no proposed arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax. Cross-check: the actor transition algebra and routing priority law. Disposition: pass for the pre-edit model. The external caller failed before production with exactly two E0277 diagnostics, both requiring Value: Ord at protocol identity and base projection. No route, message, or heap-storage error appeared.

The focused caller and all 827 workspace Nextest cases pass after the bound move. The production module changed +1/-3, net two fewer physical lines (446 → 444); no transition branch changed. Its control phases remain Active/Exhausted, the heap still owns the same entries, and all priority comparison remains on construction and Behavior. Subordinate alternatives, modules, public spellings, effect lanes, and interpreter operations are unchanged. The residue scan found no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax. The actor transition and routing priority laws were cross-checked. Disposition: pass for this bound-only stage; A13 remains open.

No-op and compiler-friction checkpoint for the three A13 bound batches: they remove 21 net production lines of repeated read-only/identity bounds, with zero new public types, traits, policies, adapters, or wrapper syntax. An unrelated BehaviorLayer does not require a caller edit, and no public name describes structural position. The external test file grew 47 net lines of direct compile witnesses; eight aliases (11 physical lines) name existing concrete routes and products, so test protocol plumbing did not exceed the 21-line production deletion. No test supplies a no-op policy or discarded effect to satisfy the new surface. The remaining Router trait-level bound is a separate design question rather than compiler fallout from these edits.

A13 pre-edit protocol-bound law

The next A13 protocol-identity witness is WorkQueue with a ReplyRoute<ExactDestination> worker route. ReplyRoute is a sealed, lawful DeliveryRoute and can carry logical or exact recipients, but deliberately does not claim PartialEq between them. The derived identity law requires only the address and the two route protocol/message relationships to name WorkQueueMessage; worker-route cloning and equality belong to queue state inspection and availability transitions. The caller syntax is an external Protocol<Addr = ExactAddr, Msg = WorkQueueMessage<...>> bound, with no construction or transition. On the prior representation the intended focused test must fail solely because the aggregate declaration and protocol impl require ReplyRoute<ExactDestination>: PartialEq. The existing protocol-only caller suite, Recipient, ReplyRoute, and DeliveryRoute are the lower-order witnesses. The candidate moves the bound to existing methods/Behavior, adds no semantic state, effect, public type, or runtime port. Its control states, subordinate alternatives, branches, modules, and public spellings stay unchanged; the route remains the same owned field. No history, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax is proposed. Cross-checks: actor-transition-algebra.md, behavior-layer-laws.md, and the normalized FIFO law. Disposition: pass for the pre-edit model, pending the red caller witness and measured implementation.

The first draft witness also failed because the ordinary MailAddr lacks an exact-endpoint family; that failure was unrelated to route equality. The corrected external caller uses an EndpointAddress and failed with only E0277: ReplyRoute<ExactDestination> does not implement PartialEq, which the previous WorkQueue declaration demanded. Moving Clone + PartialEq from the aggregate declaration, BehaviorBase, and Protocol to the existing construction/transition impls made that caller compile without changing queue operation. The measured source change is production +7/-4/net +3, including the public bound explanation, test +35/-3/net +32, and public API +0/-0 types. The one aggregate module grows from 263 to 266 production lines; the direct state product remains capacity, available workers, and waiting jobs, with no control-state enum or subordinate sum. The five production if selections and three command arms remain eight transition branches by the same count before and after. Every stored route is still required for later dispatch or withdrawal. The residue scan found no new arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax. Disposition: pass for this protocol-bound batch; the rest of A13 remains open. The focused debug and optimized caller tests, two FIFO unit tests, workspace all-target compile, all 824 workspace Nextest cases, and the documentation book build passed through Nix. The complete nix flake check -L passed all ten declared checks at signed commit 870f4b2, including the optimized 824-case Nextest run, release tests, doctests, Clippy, package, documentation, formatting, dependency-audit, and dependency-policy gates.

The same derived protocol-identity law applies to Topic and PubSub: their message sums contain owned publication, topic, and route values, and name an address, without requiring those values to be cloned, compared, or delivered. The intended caller syntax projects Protocol::Msg from each actor with non-Clone, non-Eq publication and route types. The focused actors/tests/protocol_bounds.rs compile witness must fail on the prior impls. Clone, Eq, PartialEq, and DeliveryRoute remain necessary on the actual transition impls. The lower-order TopicMessage, PubSubMessage, Protocol, and Behavior contracts already express this distinction; no new protocol, effect lane, wrapper, or interpreter capability is proposed.

Pre-edit aggregate-drift checkpoint: both actors have one membership state (Vec<Route> for Topic, Vec<TopicMembership<K, Route>> for PubSub) and the same control states, subordinate alternatives, transition branches, production lines, modules, and public spellings before and after this proposed bound change. The future-needed values are each ordered subscriber route, and for PubSub each retained topic identity. No arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax is proposed. The discovery contracts and the Protocol/Behavior distinction in actor-transition-algebra.md are cross-checked. Disposition: pass for the proposed narrower protocol law, pending its pre-edit regression and implementation.

The pre-edit caller produced ten E0277 diagnostics for transition-only DeliveryRoute, Clone, Eq, and PartialEq bounds. After narrowing only the two Protocol impls, the caller passes; the Behavior impls retain their transition bounds. Aggregate control states remain one for each actor; subordinate state and result alternatives and transition branches remain unchanged. Production lines in these two files changed from 323 and 184 to 317 and 179; modules and public spellings remain unchanged. The ordered subscriber routes and retained topic identities remain the future-needed state, with no residue from the pre-edit scan. The discovery and actor transition law cross-check remains valid. Disposition: pass for this focused bound repair; A13 remains open for the rest of the public surface.

The same identity equation also applies to Machine<A,S,M,P,E>: its protocol is (A, M), independent of phase copying and comparison. A caller must be able to project Protocol::Msg = M while P lacks Copy and PartialEq; execution still requires those bounds. The focused caller is added to actors/tests/protocol_bounds.rs before production edit. Existing Machine, Protocol, and Behavior are the only required layers, with no interpreter effect or wrapper change. Pre-edit drift checkpoint: the machine's state, held queue, phase, transition function, one control state, subordinate Advance alternatives, branch count, modules, and public spellings are unchanged by this bound proposal. Its future-needed values are the current phase, owned state and held messages. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax is proposed. The machine and actor transition law documents were cross-checked. Disposition: pass for the proposed bound repair, pending the failing caller and implementation.

The pre-edit machine caller failed with E0277 for Phase: Copy + PartialEq. After narrowing Machine's Protocol impl, it passes while its constructor, phase access, and Behavior impl retain the execution bounds. Production lines in machine.rs changed from 198 to 194; all state alternatives, transition branches, modules, and public spellings remain unchanged. The future-needed values and residue scan are unchanged from the pre-edit checkpoint. Disposition: pass for this protocol-only repair.

The next A13 protocol-bound batch applies that already-proven identity law to Configuration, Health, Readiness, and Registry. Their command types contain owned configuration or key values; naming those commands does not clone or compare them. The route and destination bounds remain on each actor struct because those types currently define its retained delivery capability; the proposed edit removes only C: Clone + Eq or K: Clone + Eq from its Protocol impl. A caller projects each exact command sum with a non-Clone, non-Eq value and a lawful concrete result route. The compile regression in actors/tests/protocol_bounds.rs precedes the four source edits. Existing Protocol, command sums, result protocols, DeliveryRoute, and Behavior are reused. No interpreter, wrapper, effect lane, or public spelling changes.

Pre-edit aggregate-drift checkpoint: configuration has one current ConfigurationState; health retains ordered component states; readiness retains ordered fixed dependencies; registry retains ordered key-recipient bindings. Their control states, subordinate alternatives, transition branches, modules, and public spellings do not change. The future-needed values remain respectively the current version/value, component evidence, dependency evidence, and key-recipient binding. There is no proposed arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax. The operations/discovery contracts and actor-transition-algebra.md were cross-checked. Expected source change: four Protocol impls, roughly four bound lines deleted; no new public type. Disposition: pass for the proposed identity-law migration, pending its failing caller and implementation.

The pre-edit caller failed with eight E0277 diagnostics, two for each actor's unneeded Clone + Eq requirement. It passes after removing only those four Protocol bound lines. Execution, construction, and retained route bounds remain unchanged. The four aggregates retain all prior current values, alternatives, transition branches, and modules; production source is four lines smaller and public spellings are unchanged. The pre-edit residue scan and law cross-check still hold. Disposition: pass for this identity-law migration. A13 remains open for bounds on other protocols and the remaining public-surface review.

The same derived identity law reaches Correlator, Acknowledgements, and Barrier: their command sums can carry non-Clone, non-Eq correlation keys, payloads, and barrier members while a lawful result route remains named. Clone/Eq are execution bounds; their structs and message sums do not require them. The caller projects the three message sums in actors/tests/protocol_bounds.rs before production edits, using the existing Recipient<MessageProtocol<...>> route. The proposed edit only removes transition bounds from three Protocol impls, reusing their existing result protocols, routes, and Behavior impls. No wrapper or interpreter path changes.

Pre-edit aggregate-drift checkpoint: correlator retains its ordered key lifecycle states; acknowledgements retains ordered records; barrier retains member order and its current generation/state. Their control states, subordinate alternatives, transition branches, modules, and public spellings are unchanged by this proposal. The future-needed values remain the keys, reply recipients, pending acknowledgement payloads, members, and generation. The residue scan finds no proposed arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax. The routing, workflow, and actor transition contracts were cross-checked. Expected source delta is four deleted bound lines, no new public types. Disposition: pass for the proposed identity-law migration, pending its failing caller and implementation.

The pre-edit caller failed with eight E0277 diagnostics for Key and Value. After removing four bound lines from the three Protocol impls, that caller passes; the execution impls retain their bounds. Current states, subordinate alternatives, branches, modules, and public spellings are unchanged. The retained values, residue scan, and routing/workflow law cross-check remain as recorded above. Disposition: pass for the focused identity-law migration.

Presence, Lease, and Workflow expose one further instance of the same derived law. Each public struct requires K: Clone + Eq merely to name its type, although its private fields can store a non-Clone, non-Eq K and its message sum can own one. The constructor and Behavior impl genuinely need those bounds for their policies; the protocol identity does not. The intended caller projects Protocol::Msg for each actor with a non-Clone, non-Eq key and a lawful result route. The compile witness is added to actors/tests/protocol_bounds.rs before touching production. The change removes the bound at each struct declaration and its Protocol impl only; constructor and execution bounds remain, and no new trait or port is needed.

Pre-edit aggregate-drift checkpoint: presence retains its ordered records and timer mapping, lease retains one vacant/held/exhausted state and timer ID, and workflow retains its validated definition and current run state. Their control states, subordinate alternatives, branches, modules, and public spellings do not change. The future-needed values are respectively the participant records, current lease holder/generation, and workflow steps and result route. No arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax is proposed. The discovery, time, workflow, and actor transition contracts were cross-checked. Expected production delta is six bounds removed across three files, three physical source lines deleted, and no new public types. Disposition: pass for the proposed bound relocation, pending the focused failing caller and implementation.

The pre-edit caller failed with six E0277 diagnostics at the three struct declarations. With their K parameters unbounded and the same bounds removed from their Protocol impls, it passes. Constructors and transitions retain their Clone + Eq requirements; the focused presence, lease, and workflow transition tests pass. The three production files contain three fewer physical lines, with unchanged states, alternatives, branches, modules, and public spellings. The future-needed values, residue scan, and cross-checked laws remain as recorded above. Disposition: pass for this bound relocation.

Router has a distinct protocol-only bound: its strategy's observation must be Clone to execute the current rollback transition, but the public RouterMessage can own an observation without cloning it. An application strategy with a non-Clone observation must still be able to name the router protocol. A focused compile caller in actors/tests/protocol_bounds.rs implements a real membership-selection and observation-update policy, then projects Protocol::Msg; it precedes the proposed one-line Protocol bound removal. RoutingStrategy, RouterMessage, Recipient, and Behavior are the existing pieces. No runtime, wrapper, or effect lane changes.

Pre-edit aggregate-drift checkpoint: router retains its ordered recipients and one concrete strategy. Its control state, subordinate alternatives, transition branches, modules, and public spellings do not change. Future decisions need that recipient order and the strategy's current observation state. No arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax is proposed. The routing and actor transition contracts were cross-checked. Expected production delta is one deleted bound line, no new public type. Disposition: pass for the proposed narrower identity law, pending the failing caller and implementation.

The pre-edit caller failed with E0277 for its owned, non-Clone observation. After deleting R::Observation: Clone from only the router's Protocol impl, it passes; the transition impl retains the rollback bound. The existing router transition tests pass. One production line was removed; state, alternatives, branches, modules, public spellings, future-needed values, and the residue scan are unchanged. Disposition: pass for this identity-law repair.

Classification: derived Rust protocol identity. A cache or resolver recipient names an address and a command type without running a transition or copying a binding definition. Thus Protocol for Cache<K,V> and Resolver<K> does not require K: Clone + Eq or V: Clone; those laws are needed by the respective transition or borrowed construction operations. The caller syntax in actors/tests/protocol_bounds.rs names each actor protocol with non-Clone, non-Eq payload types. It is the focused compile witness and must fail on the prior bounds. The existing MessageProtocol, Recipient, CacheMessage, and ResolverMessage products are reused. No new trait, alias, constructor, runtime port, wrapper obligation, or effect lane is proposed.

Aggregate-drift checkpoint: cache and resolver state, protocol sums, results, transition branches, production modules, and public spellings stay unchanged. The future-needed cache values are its ordered entries, capacity, and exact keys/values; the resolver needs its immutable key-recipient bindings. No alternative is added or deleted. The residue scan finds no proposed arrival history, duplicated cause, false cardinality, nested authority, semantic boolean, or positional syntax. The persistence and discovery contracts and the Protocol/Behavior separation in actor-transition-algebra.md are cross-checked. Disposition: pass for the narrower protocol law, pending the pre-edit regression and implementation.

The caller failed on the prior implementation with five E0277 diagnostics requiring Clone/Eq on protocol-only payloads. The same caller passes after removing those bounds from the two Protocol implementations; the bounds remain on actual transition and borrowed-construction operations. No type, module, aggregate control state, subordinate alternative, transition branch, or public spelling changed. The residue scan and law cross-check remain as recorded before the edit. Disposition: pass for these two bound repairs. The wider hidden-export and extension-port inventory in A13 remains open.

Compile-cost comparison for those two bounds, on aarch64-darwin with the Nix-provided Rust 1.95 toolchain: two detached checkouts at 1559a87 differed only by restoring K: Clone + Eq, V: Clone to Cache's Protocol impl and K: Clone + Eq to Resolver's Protocol impl. Both used the same warm CARGO_TARGET_DIR, CARGO_BUILD_JOBS=2, CARGO_INCREMENTAL=0, and cargo check -p bombay-behavior-actors --lib --locked. Before each measured run, cargo clean -p bombay-behavior-actors removed only the actor package's artifacts. Both runs visibly checked that crate: restored bounds took 187.07 seconds wall time; narrower bounds took 187.84 seconds. The 0.77-second difference is under 1% and does not establish a compile-time improvement. The supported benefit is the narrower protocol law and the removal of five misleading E0277 caller diagnostics. This pair does not measure every generic bound or the full workspace build.

The public FifoError and KeyedError sums are application-visible aggregate failure contracts, and FixedBuilder is the inferred application construction value. The trusted core initialize and delegate_transition ports and the RoutedCreation child-host value are required by wrapper or interpreter authors. Their existing rustdoc describes the relevant trust and custody rules; the #[doc(hidden)] markers were removed so readers can find those contracts. This changes documentation visibility only. Other hidden generated obligations and runtime ports still need the full ownership classification before A13 can close.

The follow-up inventory found a second hiding site for KeyedError and FixedBuilder: their atomic re-exports still shared #[doc(hidden)] groups with interpreter products. They now belong to the visible re-export groups. The Nix-pinned Rustdoc build succeeded, and target/doc/behavior_actors/atomic/index.html contains direct public links to both items. The public-surface inventory classifies the remaining annotation sites. Trait implementor ownership and a repeatable compile-cost comparison remain open before A13 can close.

A13 FIFO aggregate error export, before implementation

Classification: deliberate Bombay public error policy, not an actor-model law. FifoError is the FIFO aggregate's complete transition-failure sum, with distinct InitializationUnavailable and WorkerCreationsExhausted alternatives. An application that owns FIFO initialization must be able to match those alternatives without naming the private fifo_pool module, just as it can match the sibling KeyedError. The intended caller syntax is behavior_actors::atomic::FifoError in an exhaustive match. The external actors/tests/protocol_bounds.rs fixture will first require that path and must fail before the re-export; then it will pass after the smallest atomic visibility edit. The runtime-facing Behavior::Error remains the same type and no failure or ownership transition changes.

Aggregate-drift checkpoint: FIFO control states remain Constructed, Operating, Draining, Stopped, and ForcedRetirement. Subordinate states, result alternatives, transition branches, and module count are unchanged by the proposed re-export. The retained current values are the prepared workers, operating members/backlog/cursor, draining workers/deadline, and terminal forced-retirement members/cause in their existing variants. A12 still owns the question of whether every terminal field is needed. Public spellings increase by one, with zero public types added or removed. The edit adds no arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural user syntax. It is cross-checked with actor-transition-algebra.md, the FIFO law, and the existing aggregate error vocabulary. Expected files: atomic/mod.rs, the external compile fixture, and this audit; expected production line delta is zero or one. The external caller failed before the edit with E0432 for the inaccessible behavior_actors::atomic::FifoError path and passed after the one-spelling re-export. The production diff is +1/-1 line; no type, state, alternative, transition branch, or module changed. The existing two alternatives and their error displays are unchanged. The Nix-pinned Rustdoc build passed and the public atomic index links FifoError alongside KeyedError and FixedBuilder. The residue scan and law cross-check remain as recorded above. Disposition: pass for this export repair; A13's wider trait ownership and compile-cost review remains open.

A13 authored-role and logical-product documentation, before edit

Classification: Rust caller contract and derived typed-composition policy. A manually authored direct-child role lawfully implements ChildRole and ChildOccurrence with DeclaredChildOccurrence; an application host can constrain the exact logical-host product with BirthProtocolProduct. Both are existing external caller paths in established_capabilities.rs and logical_host_requirements.rs. Their public proof names and the required ChildOccurrence::Resolution associated type must be discoverable in Rustdoc. Before editing, a Nix-pinned cargo doc -p bombay-behavior --no-deps build succeeded but the crate index omitted DeclaredChildOccurrence and BirthProtocolProduct, and the declared-occurrence page was absent. The private Recipient::new has an ineffective #[doc(hidden)] marker to remove. The intended edit changes documentation display only; it adds no alias, default, bound, constructor, implementor, actor transition, or runtime port.

Aggregate-drift checkpoint: all actor control states, subordinate alternatives, transition branches, production modules, and public spellings are identical before and after. The future-needed role values remain its declared parent, child behavior, and structural position; the logical product retains its ordered protocol occurrences. Four ineffective or misleading documentation markers are removed, with no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural user syntax. The actor-transition, creation, and logical-host laws are cross-checked. Disposition: pass for the model; Rustdoc visibility and external caller witnesses still need post-edit verification.

The four markers were removed as modeled. The core annotation count fell from 22 to 18; no visibility modifier, trait bound, type, implementation, aggregate state, branch, module, or public spelling changed. The Nix-pinned Rustdoc index now links both DeclaredChildOccurrence and BirthProtocolProduct, and both documentation pages exist. The established_capabilities and logical_host_requirements external caller suites passed 20 tests, including manual nominal occurrence and generic logical-host use. The residue scan and law cross-check remain as recorded above. Disposition: pass for the documentation repair. A13's wider trait implementor and compile-cost review remains open.

A15 coding-rule progress

Timer-domain tests now call the mutating accept operation before assertions, so optimized and debug test profiles execute the same transition. Generated readiness cases use the closed ReadinessStatus sum rather than a semantic boolean. The pool-private values formerly named only Operating are now FifoOperating and KeyedOperating; each remains under its existing root state variant with no state or branch change. The nested .sends.inner.inner uses in testkit/tests/compositions.rs are structural composition tests that explicitly assert nesting order. All 92 rustdoc import lines across 26 source files now use qualified paths or were removed where the negative example tested only a missing alias. scripts/check_rustdoc_imports.py enforces that rule in the Nix documentation gate; a hidden-import counterexample fails the check. Core delivery compile-fail examples now require only Protocol, the capability they actually test, rather than an inert Behavior fixture. Direct rustc --error-format=json probes of the three logical-delivery examples produced only E0308; replacing the wrong protocol, address, or payload with the declared one compiled in each case. Rustdoc's compile_fail,E0308 tag alone does not enforce that error code, so this counterfactual check supplies the failure-reason evidence. A direct compiler check now validates the expected diagnostic for all 45 tagged compile-fail snippets in the Nix documentation gate; it found and corrected five stale tags. The optimized timer-domain tests passed both cases, and nix flake check passed all ten checks on aarch64-darwin, including the documentation and doctest gates. The post-check edits in this audit batch only add the A11 inventory and this verification result; its Rustdoc examples, scripts, and Nix gate definition are the checked snapshot. Disposition: pass.

A15 timer admission outcome, before implementation

The earlier A15 pass covered the listed fixtures, but a repository-wide scan found a remaining semantic boolean: TimerLease::accept and OneShotSchedule::accept mutate the schedule and return bool. Their callers use that value to choose whether to run a timer reaction. Reopen A15 for this specific policy violation; the prior evidence remains valid for its scope.

Classification: deliberate Bombay timer policy, not an actor-model guarantee. An event matching the currently armed timer is admitted once and consumes that schedule. A foreign, stale, duplicate, cancelled, or exhausted event is ignored without changing schedule state. The complete local result is TimerAdmission::{Accepted, Ignored}; the wrapper still emits the same Actions and invokes the same reaction only on Accepted. The caller syntax matches that sum instead of using a mutating boolean in a guard. The focused domain regression checks exact, duplicate, cancelled, foreign-ID, and foreign-generation arrivals, including the surviving schedule. Existing timer-wrapper tests and both wrapper orders remain lower-order witnesses.

Pre-edit aggregate-drift checkpoint: TimerLease retains its four states (NeverIssued, Armed, Idle, Exhausted), and OneShotSchedule retains its two states (Unscheduled, Scheduled). The new return sum represents one transition's disposition; it stores no future state. The future-needed values remain the armed generation and the one-shot ID, generation, and deadline. No actor aggregate state, public spelling, or effect lane changes. The edit is expected to touch the domain and four wrappers, replacing two boolean returns and four guard uses with one private sum and exhaustive matches. Record exact line, branch, and module deltas after the edit. The residue scan found no arrival history, repeated cause, false cardinality, nested transition authority, or positional user syntax. Cross-check the explicit effect law in docs/actor-transition-algebra.md and the timer wrapper Rustdoc. Disposition: pass for the pre-edit model.

The pre-edit Nix-toolchain compile witness failed with seven E0433 diagnostics because TimerAdmission did not exist. After implementation, the two mutating domain operations return the private Accepted | Ignored sum, and Deadline, OneShot, Periodic, and ReceiveTimeout match it exhaustively. The original ID guard and all action lanes remain in place. Domain tests passed 3/3 in debug and optimized builds; all nine actor time unit tests passed in both profiles. The actor timer-settlement integration target passed 4/4, including both wrapper orders, and the independent receive-timeout model target passed 6/6. Full repository gates remain pending for this batch.

Post-edit aggregate-drift checkpoint: TimerLease remains four states and OneShotSchedule two; no stored subordinate alternative or future-needed value changed. The former boolean result is the new two-case local admission sum. Across the four wrappers, top-level event arms changed from 12 to 11 because Deadline now matches its owned arrival once; eight explicit admission arms replace four boolean guard decisions. The five affected modules remain five, and no public spelling changed. Measured production diff is +56/-34 (net +22) lines; the focused tests are +22/-3 (net +19). This is a domain-model repair, not a code-reduction claim. No arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax remains in this timer admission path. The actor effect law and all four wrapper Rustdoc contracts were cross-checked. Disposition: pass for this retained batch, pending the full Nix gate before A15 closes.

The same scan found InactivityModel::notification in the independent testkit: it consumes a live token, returns a semantic bool, and three caller assertions perform that mutation inside assert!. This is a second A15 checkpoint. The testkit policy is that one matching notification consumes and returns its exact current token; a stale or duplicate notification returns absence and leaves the live token unchanged. Option<u64> is the direct domain representation of one accepted token or absence, with no new protocol type. The caller must bind the outcome before asserting, so debug and optimized builds execute the same transition. A focused testkit caller expecting Some(1) versus None is the pre-edit compile regression. The lower-order witnesses are the existing receive-timeout model trace, the actor timer-domain test, and both timer wrapper orders. This changes no production actor state, interpreter path, or effect lane. The model keeps its two optional tokens; its future-needed value is still the current live token. Expected files are the model and its one caller test. Record post-edit measurements and gates before closing A15.

The standalone Nix-pinned rustc caller included the actual testkit model module and required notification to return Option<u64>. Before the edit it failed with the intended E0308 (bool versus Option<u64>); afterward it compiled. The 6-test independent receive-timeout trace passed in debug and optimized builds. It now binds each admission before asserting, checks that a stale notification leaves token 1 live, and checks that an accepted one returns that same token. The model still uses two optional tokens and the same two transition branches; it adds no public type, state, module, or effect lane. Measured testkit model diff is +4/-5 (net -1) lines and its caller test is +7/-3 (net +4). The retained current values remain the last issued token and the one live token. The residue scan found no arrival-history alternative, repeated cause, false cardinality, nested authority, semantic boolean, or positional syntax in this path. Cross-check against the receive-timeout Rustdoc and the actor transition effect law passed. Disposition: pass for this batch; A15 awaits the full Nix gate on the signed revision.

A whole-crate assertion scan found additional test and fuzz assertions that called state-changing methods inside the macro: actor transition, model initialize/activity, collection insert/remove, mailbox receive, sequence issue/reserve, and iterator next. The test-execution law is that setup and transitions run before observation; assertions inspect retained results and complete actions only. This is test discipline, not a new actor transition. The calls were moved to named locals in their original order, including four observational iterator calls, across 34 Rust files (+304/-258 lines, net +46). All changes are in test or fuzz code, including inline test modules; no production type, state, effect lane, or branch changed. A repeated whole-crate scan for these methods inside assertion macros found zero sites. The Nix-pinned workspace Nextest run after this batch passed 819/819 tests, including the macro dependency-resolution fixtures and the affected actor, core, and testkit suites. The changed fuzz targets and clean-snapshot flake gate remain to be checked.

The next A15 scan found five generated bool selectors in the independent testkit models. Each selected a domain event or exact/foreign source; the tuple generators also supplied values unused by some event alternatives. This is a test-model policy issue, not a new actor law. Before editing, the static scan rg 'any::<bool>\(\)' crates --glob '*.rs' found exactly these five sites. The expected regression is that the same scan finds none after the edit, while the three affected model targets still compare every generated turn with their independent oracle in debug and optimized builds. The direct test data model is a separate closed sum for buffer, priority, rate, lease, and observation operations, with each variant owning only the data it uses. No production state, effect product, interpreter path, or public spelling is changed. The five-site static regression now finds no any::<bool>() under crates/. The three edited test binaries passed 7/7 cases in both debug and release mode with the Nix-pinned toolchain. Their measured test-only diff is +219/-137 (net +82) lines; production is +0/-0, with no public API change. Production control states, subordinate alternatives, transition branches, and modules are unchanged. The independent models retain their prior observable decisions. Five boolean event/source selectors and two numeric operation tags became seven closed input sums with 18 alternatives. Each alternative owns its current event data, such as an offered value, acquired cost, exact report target, or elapsed timer source. The three test modules remain three. The residue scan found no retained arrival history, repeated cause, false cardinality, nested transition authority, semantic selector boolean, or unused field on these generated operations. The actor transition and relevant routing, timing, and observation laws were cross-checked. Disposition: pass for this test-model batch; the complete A15 gate remains open.

A wider assertion scan then found mutating helper calls hidden behind local names such as query, put, acquire, release, hold, and offer, plus interpreter methods called inside assertions. The earlier method-name scan did not catch these. Hoist those transitions and ownership transfers before assertions, run the affected tests, and repeat the broader scan before A15 can close.

The follow-up batch hoisted local actor transitions, interpreter calls, initialization, creation decomposition, source admission, and consuming iteration before their assertions. It also replaced 91 assertion-side unattempted().into_inputs().len()/is_empty(), into_requests().len()/is_empty(), and into_deliveries().is_empty() chains with existing borrowed len, is_empty, or as_slice().is_empty observations. The direct forms inspect the same ordered product without transferring custody merely to count it. Across 25 Rust files the test-only diff is +206/-663 (net -457) lines; production is +0/-0 and public API, actor control states, effect lanes, transition branches, and module count are unchanged. All source-file edits are inside #[cfg(test)]; the remaining files are tests or fuzz targets. The surviving current values are the original actor state and exact owned effect products; no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer path was added. The actor transition and source-custody laws were cross-checked. The broader assertion scan now finds no selected mutating or consuming method inside an assertion; its ten remaining &mut matches compare a returned source with a temporary source and do not invoke a transition. Workspace test compilation and formatting passed. Local Nextest discovery and a direct actor test binary then stalled in macOS _dyld_start before the Rust harness ran, so that run is not test evidence. scripts/check_assertion_effects.py now enforces the identified consuming-method and mutating-helper patterns in the Nix document gate; five checker regression cases cover detection and allowed observation. The local checker and its tests passed. A clean-snapshot Nix gate and changed fuzz-target build remain required before this batch or A15 can close.

The clean detached snapshot at signed commit 9c9973e passed nix flake check --max-jobs 1 --no-write-lock-file, including package, Nextest, Clippy, Rustdoc, doctests, formatting, deny, and the document gate with both assertion-checker scripts in the flake source set. The Nix-provided fuzz runner then built all manifest targets after the assertion edits with nix run .#fuzz -- build; its separate lockfile was synchronized to the workspace crate versions. These runs complete the pending A15 verification. The later A20 priority-property edit has its own focused baseline and counterfactual evidence and does not change the A15 assertion discipline. Disposition: pass; A15 is closed.

A07 actor mutation evidence: routing-buffer capacity

At revision 0274dab, a focused campaign mutated the bounded buffer's below-capacity guard (routing/buffer.rs:261). The law is Bombay's declared overflow policy: an offer below capacity is retained, while an offer at capacity follows the configured rejection or eviction branch and preserves ownership of every value. The actor unit tests and the independent FIFO and overflow property in behavior-testkit/tests/routing_invariants.rs are the relevant witnesses.

The command selected bombay-behavior-actors, filtered to the guard and its comparison operators, and set --test-workspace true --test-tool nextest --no-shuffle --minimum-test-timeout 180 -- --profile mutants with PROPTEST_CASES=32. The mutation log confirmed test_packages=All for each mutant. The unmutated baseline passed; all five selected mutants built and were caught by actor buffer tests, primarily every_overflow_policy_preserves_or_returns_all_owned_values. This is a five-mutant routing-law result, not an actor-wide mutation verdict. A07 still needs independently reviewable campaigns for the other actor families and a separate viability ratchet.

A07 stable-proxy activation admission experiment, before simplification

Classification: derived exact-correlation law. BeginActivation consumes one ActivationPermit and issues an ActivationAttempt containing that permit's WorkerAttempt. Every WorkerActivation constructor in atomic/worker/activation.rs carries that same worker evidence alongside the attempt; its fields are private, and the permit cannot be duplicated. Thus a matching activation attempt already proves the matching worker for every constructible input. The public transition still accepts only its exact activation and returns a foreign input intact through the diagnostic lane. The caller syntax is a normal StableProxy::on(request.started()), including two independently constructed requests with equal worker payload and endpoint values but different non-forgeable attempt tokens.

At signed revision 855458a, the Nix-pinned campaign first selected the only mutant in stable_proxy/state.rs; it was unviable because ProxyPhase has no Default, so it supplied no mutation verdict. Its unmutated baseline ran 590 actor tests. The separate activation-guard campaign selected all five mutations at stable_proxy/mod.rs:314 and ran 702 actor/testkit tests per mutant; it skipped a second baseline, while the full 812-test workspace run had passed at this revision. Four were caught; changing && to || survived. The survivor falsified the claim that both comparisons are independently necessary; existing tests already reject foreign activation. The focused caller regression distinguished exact attempt tokens despite equal payload and endpoint values. It passed before and after the edit; the complete 51-test proxy recovery suite and optimized focused witness also passed after it. The private guard now retains only the exact activation comparison and deletes the redundant worker input. No public type, effect lane, interpreter operation, wrapper, or actor-model law changed. The existing activation and shutdown models remain the lower-order transition witnesses.

Aggregate-drift checkpoint before the edit: stable proxy's control states are Dormant, Starting, Ready, EmptyInitial, EmptyAfter, Replacing, ShuttingDown, and Stopped; they remain the same. No subordinate state or result alternative, production module, or public spelling changes. The only transition branch affected is the exact activation admission predicate. Every surviving state keeps the same current worker, attempt, activation plan, and pending custody. The proposal stores no arrival history or repeated cause, assumes no cardinality, adds no nested transition authority or semantic boolean, and exposes no positional syntax. It is cross-checked with the stable-proxy and atomic actor laws and the complete-effect rule in actor-transition-algebra.md. Expected and actual files: this audit, one proxy caller test, and stable_proxy/mod.rs. The production diff is +7/-11 lines, net -4; the test adds 47 lines. Public types added/removed: 0/0. Control states, subordinate alternatives, transition branch count, modules, and public spellings remain unchanged. The exact retained current values and residue scan remain as recorded before the edit. At signed revision 7163ec3, the Nix-pinned post-edit campaign ran a 591-test actor baseline and selected the remaining viable equality mutation. The mutated build ran 703 actor/testkit tests; six actor tests failed, so the mutant was caught. The unselected function-wide replacement proposes Ok(Default::default()), which cannot construct the returned affine activation. This is a stable-proxy activation-law verdict, not an actor-wide result. The full Nix flake gate passed from a clean worktree at 7163ec3, including workspace Nextest, Clippy, docs, doctests, formatting, dependency policy, and packaging. Disposition: pass for the retained representation and focused mutation slice.

A07 actor mutation evidence: FIFO completion correlation

Classification: Bombay's creator-local correlation and assignment-custody policy. A worker completion has exact assignment authority, while its outer ChildReport separately names the child creation. The pool accepts a completion only when both identify the current busy worker. A foreign child report must not release the assignment or send a completed customer outcome. At signed revision 0a40bdc, a Nix-pinned campaign selected the three guard mutations at fifo_pool/mod.rs:276: unconditional true, unconditional false, and inverted child-ID equality. The baseline ran 591 actor tests; the full Nix gate had passed on the same production code at 7163ec3. Every mutated command selected the 813-test workspace suite. All three mutants built and were caught. fifo_pool::delivery_and_completion_orders_complete_once caught unconditional acceptance; the FIFO correlation suite caught rejection and inversion. No production edit was needed. This is one FIFO correlation-law slice, not a full FIFO mutation campaign or an actor-wide verdict.

A07 actor mutation evidence: keyed binding expectations

Classification: Bombay's keyed-binding compare-and-set policy. A binding command carries the expectation it observed; a stale generation returns the complete command and current expectation without changing placement. A rebalance to the already bound role returns the existing binding. At signed revision 0a40bdc, a separate Nix-pinned campaign inverted the two guards at keyed_pool/mod.rs:1069 and :1146. Its baseline ran 591 actor tests; mutated commands selected the 813-test workspace suite. Both mutants built and were caught by the keyed construction-and-commands integration test, which checks generations, owned rejection, and an independent directory placement. No production edit was needed. This is a keyed binding-law slice; other keyed and actor-family laws still require mutation review.

A07 actor mutation evidence: dynamic cancellation authority

Classification: Bombay's keyed-operation correlation and affine authority policy. Cancellation of a live service requires the exact current operation; the actor returns a stale authority unchanged and retains the active entry. At signed revision f9f39dc, a Nix-pinned campaign inverted the operation comparison at dynamic_supervisor/mod.rs:885. Its baseline passed 591 actor tests; the mutated build selected the 814-test workspace suite. The mutant built and was caught by four dynamic integration tests, including accepted_start_cancellation_retires_before_fresh_key_reuse. A separate isolated counterfactual changed != to >: current authority still passed the guard, but an older authority for the same reused key was accepted. The focused integration test failed exactly at its stale-after-reuse assertion (dynamic.rs:3309). The counterfactual was reverted. No branch production edit was needed. This is one dynamic-supervision law slice, not a full family campaign. The full Nix flake gate passed all ten checks on f9f39dc before the counterfactual; the latter ran in a separate detached worktree.

A07 actor mutation evidence: fixed replacement correlation

Classification: Bombay's exact predecessor-correlation and returned-custody policy. A fixed supervisor accepts a replacement outcome only while that member awaits an outcome for the same predecessor worker. A foreign outcome returns unchanged with the pending member; a matching outcome remains held until the independent predecessor-stop leg resolves. At signed revision ebcfa9d, a Nix-pinned campaign selected three mutations at fixed_supervisor/recovery/mod.rs:1876: unconditional guard acceptance, unconditional refusal, and inverted predecessor equality. Its baseline passed 591 actor tests; each mutated build selected the 814-test workspace suite. All three built and were caught. The foreign-outcome integration test caught unconditional acceptance; valid replacement and coordinated-restart tests caught refusal and inversion. No production edit was needed. This is one fixed-supervision replacement-law slice, not a full family campaign.

A07 child creation resolution regression, before test edit

Classification: Bombay's exact staged-creation correlation policy. A ChildShutdownPlan may mark a declared child established only when both the reported creation ID and creation kind equal the values stored in that child's Awaiting state. A report with exactly one mismatched component returns the complete report, leaves the child awaiting, and permits the later exact report. The existing test used a replacement report with both components mismatched, so replacing the || admission rejection with && passed every actor test; the workspace mutant was mislabeled caught only when unrelated macro fixture tests timed out. A focused test will present wrong-kind/same-ID and right-kind/wrong-ID reports independently before the exact birth. No production type, bound, wrapper, interpreter port, transition branch, or public spelling changes.

Aggregate-drift checkpoint: Planning remains Collecting or Reported; each child remains NotRequested, Awaiting { creation, kind }, or Established { creation }. The future-needed values are the declared position, exact staged ID and kind while awaiting, and committed ID for plan construction. Production states, subordinate alternatives, branches, lines, modules, and public spellings are unchanged before and after this test-only experiment. The residue scan finds no arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or structural user syntax. This is cross-checked with actor-transition-algebra.md and atomic-runtime-settlement.md. Disposition: pass for the regression model; the focused counterfactual and baseline still need verification.

A05 nested test-timeout verdict, before implementation

Classification: deliberate Bombay verification policy. A CaughtMutant summary is not proof that a law assertion failed when the selected test runner itself timed out a test and returned failure. The verdict must reject any selected mutant whose Nextest log contains a timed-out test, even if another test failed, and must require inspectable log evidence for every claimed caught mutant. A focused gate fixture will submit a complete, otherwise valid campaign with CaughtMutant and a Nextest TIMEOUT line; the prior gate accepts it. The implementation will reuse cargo-mutants' log_path and existing Outcome/candidate identity, and the Nix mutation profile will let the outer cargo-mutants timeout classify genuinely stalled commands. No actor algebra, aggregate state, transition, interpreter effect, public Rust spelling, or wrapper changes.

Aggregate-drift checkpoint: actor control states, subordinate alternatives, branches, production lines, modules, and public spellings are unchanged; the gate adds only report validation and removes the runner's premature timeout. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural user syntax enters actor code. The gate law is cross-checked with the A05 report-identity law above and the Nix mutation derivation. Disposition: pass for the pre-edit model; the failing fixture and retained verdict still need verification.

The adversarial gate fixture failed on the prior implementation: check returned Ok(()) for a complete CaughtMutant report whose only Nextest evidence was TIMEOUT. The repaired gate requires a safe relative log path and a FAIL test line for each caught mutant, rejects any TIMEOUT line even alongside a failure, and applies the same validation when seeding a baseline. The mutation Nextest profile no longer terminates individual tests after ten seconds; cargo-mutants owns the command timeout and reports Timeout to the strict verdict. All 12 gate tests, targeted Clippy, and formatting passed. The actual three-mutant child-creation campaign passed the repaired verdict (3 viable / 3 total) with three test failures and zero timeouts. The gate's production portion grew from 252 to 294 lines; its test portion added 62 net lines. The actor file added 46 test lines and no production lines; the Nextest profile shrank from six to four lines. Aggregate states, alternatives, branches, modules, and public spellings remain unchanged. The residue scan and law cross-check remain as recorded above. Disposition: pass for this verification repair. The full Nix flake gate passed all ten aarch64-darwin checks on signed revision 81bda41.

A07 actor mutation evidence: catalogue correlation and admission

At signed revision 337bc2e, one Nix-pinned campaign selected ten mutations across registry unbinding, child creation settlement, configuration version conflict, one-shot timer admission, and barrier duplicate arrival. The baseline passed 591 actor tests; mutated commands selected the 814-test workspace. Every mutant built and cargo-mutants labeled every one caught, but one label was false evidence: the child-creation || to && mutant passed all actor tests, while four unrelated macro fixture tests hit the ten-second Nextest timeout. The other nine mutants had named actor test failures. The focused child-creation regression on 81bda41 passed unmutated and failed under || to && at the wrong-kind/same-ID assertion. A separate Nix-pinned, actor-only rerun selected all three current creation-correlation mutations; its 593-test baseline passed, all three mutants built and failed actor assertions, and the strengthened gate accepted its complete report with no timeout, miss, or unviable candidate. This closes the false-positive slice; other catalogue laws still need review, so A07 remains open.

Family and lawOriginal mutation result with a real actor oracle
Registry: exact recipient required to unbindOne inversion caught by discovery::registry::tests::mutations_are_atomic_and_stale_unbind_is_typed.
Child shutdown: exact creation ID and kindTwo comparison inversions caught by child-shutdown tests; the initially false `
Configuration: same-version equalityOne inversion caught by operations::configuration::tests::stale_and_conflicting_candidates_return_ownership_atomically.
One-shot timer: ID and generation admissionGuard-true, guard-false, && to `
Barrier: duplicate participant arrivalOne inversion caught by workflow::barrier::tests::generation_releases_exact_membership_in_arrival_order.

A07 actor mutation evidence: state and ownership

Classification: derived state-transition and returned-custody laws. A machine replays held messages when Goto changes phase, a stash releases its held FIFO when its route admits delivery, and a cache evicts the oldest entry only when an absent key enters a full cache. Replacing an existing key returns its old value without evicting another entry. At signed revision c3a54b3, a Nix-pinned actor-only campaign selected four mutations: machine phase equality, stash drain removal, cache && to ||, and cache capacity equality. Its baseline passed 593 actor tests. All four mutants built and failed named actor tests, with zero misses, timeouts, or unviable candidates. Machine and stash failures came from algebra; both cache mutations failed its recency and replacement-custody tests. The repaired mutation verdict accepted the complete report (4 viable / 4 total). No production edit was needed. These are three law slices; the actor-wide 3,125-candidate inventory is not claimed as fully tested.

A07 actor mutation evidence: lease renewal authority

Classification: derived generation-correlation law. A held lease may renew only when both the holder and observed generation match its current state. A stale generation or different holder returns a typed rejection without scheduling a new expiry. The independent model in timing_invariants compares the outcome, scheduled generation, and state after each generated operation.

At signed revision a334b0b, a Nix-toolchain campaign selected all eight mutations of Lease::successor with cargo mutants --package bombay-behavior-actors --test-package bombay-behavior-actors --test-package bombay-behavior-testkit --test-tool nextest --no-shuffle --minimum-test-timeout 180 -f crates/actors/src/time/lease.rs -F successor. The unmutated actor baseline passed 593 tests; a separate unmutated testkit run passed 112 tests, including the independent lease model. Mutated commands selected both packages (705 tests). Seven candidates compiled and failed named tests; the eighth was unviable because TimerGeneration has no Default. There were no survivors or timeouts. The strict mutation gate accepted the complete report with a viability floor of seven (7 viable / 8 total), keeping compiler rejection distinct from test detection. The false stale-generation guard was caught by the independent model; the other six viable changes were caught by lease unit tests. This is one lease law slice, not an actor-wide verdict.

A07 actor mutation evidence: termination observation and propagation

Classification: derived exact-correlation and terminal-custody laws. A termination monitor consumes only the selected peer or observation report in its lawful phase. A propagation target accepts one matching terminal report; foreign or later reports return their complete value without changing state.

At signed revision 812fe86, the Nix-toolchain monitor campaign selected all ten TerminationObservationTarget::react candidates in lifecycle/termination_monitor.rs. Its actor baseline passed 593 tests, and mutated commands selected actor and testkit suites (705 tests). Eight viable mutations failed named actor or independent-model tests; two whole-function replacements could not compile because Actions has no Default. No survivor or timeout occurred, and the strict gate accepted 8 viable / 10 total. Both lifecycle campaigns used cargo mutants --package bombay-behavior-actors --test-package bombay-behavior-actors --test-package bombay-behavior-testkit --test-tool nextest --no-shuffle --minimum-test-timeout 180; reproduce the monitor selection with -f crates/actors/src/lifecycle/termination_monitor.rs -F '::react'.

The matching propagation campaign selected nine correlation mutations in lifecycle/termination_propagation.rs. Eight were caught, but replacing PeerTermination::matches with unconditional acceptance survived: the peer test exercised only a matching report. The strict gate correctly rejected that original report. Signed commit f0dce34 added a foreign-peer report that must return intact while observation remains active, followed by an accepted selected-peer report; it also made the independent child-sequence model inspect initialization and every successful effect lane. Both focused tests passed. A separate one-mutant rerun failed the new peer test, with no timeout, and the strict gate accepted its complete 1 viable / 1 total report. The original eight results and the focused rerun are separate revision-specific evidence, not a claim that all actor mutations were run. The propagation selection is reproducible with -f crates/actors/src/lifecycle/termination_propagation.rs -F '::matches|match guard self.state|replace && with'.

A07 actor mutation evidence: work admission and availability

Classification: deliberate Bombay FIFO and bounded-admission policy. A submission consumes the oldest available worker or joins the bounded waiting queue; at capacity its complete value is returned. An availability notice dispatches the oldest waiting value or joins the unique worker queue.

At signed revision 69adab4, the Nix-toolchain campaign selected four WorkQueue::submit and WorkQueue::announce candidates in routing/work_queue.rs. The actor baseline passed, and mutated commands ran the actor and testkit suites. Both whole-function default replacements were unviable because the complete Actions product has no Default. The two viable admission and duplicate-availability guard changes compiled and failed named work-queue unit tests. The strict gate accepted 2 viable / 4 total, with no survivor or timeout. Reproduce with cargo mutants --package bombay-behavior-actors --test-package bombay-behavior-actors --test-package bombay-behavior-testkit --test-tool nextest --no-shuffle --minimum-test-timeout 180 -f crates/actors/src/routing/work_queue.rs -F '::submit|::announce'. The independent two-FIFO property was subsequently strengthened to inspect all action lanes with non-Clone work values and unique reply destinations; this newer oracle passed, but was not part of the earlier mutant verdict.

A07 actor mutation evidence: keyed publication membership

Classification: deliberate Bombay keyed-membership and ordered-publication policy. A topic is retained after its last subscriber leaves; a repeated subscription is idempotent. Unsubscription of an unknown topic or absent recipient returns the complete command without changing membership.

At signed revision d7d0832, a Nix-toolchain campaign selected all six PubSub::subscribe and PubSub::unsubscribe candidates in discovery/pub_sub.rs. The actor baseline passed, every candidate compiled, and named pub-sub unit tests failed under each mutation. The strict gate accepted 6 viable / 6 total, with no survivor or timeout. Reproduce with cargo mutants --package bombay-behavior-actors --test-package bombay-behavior-actors --test-package bombay-behavior-testkit --test-tool nextest --no-shuffle --minimum-test-timeout 180 -f crates/actors/src/discovery/pub_sub.rs -F 'PubSub<A, K, P, Route>::subscribe|PubSub<A, K, P, Route>::unsubscribe'. A later independent sequence model checks topic order, exact membership, every successful action lane, and rejected publication custody with distinct owned strings. It passed after the campaign and is not credited with the earlier mutant kills. Publication-loop and downstream delivery laws remain outside this mutation slice. Aggregate-drift checkpoint for the test-only batch: control states 1 → 1 (active), named subordinate state sums 0 → 0, aggregate error variants 3 → 3, message arms 3 → 3, production lines 234 → 234, modules 1 → 1, and public spellings unchanged. The current topic key, retained membership list, and introduction order remain the only future-needed values. The test's map and order list model the observable order; no production arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural user syntax was added. Cross-checks were actor-transition-algebra.md, atomic-runtime-settlement.md, and the PubSub row in engineering/atomic-actor-other-templates.md. Disposition: pass for this test-only evidence batch; capacity, retirement, and delivery settlement remain independent future laws in that normalized catalogue record.

A second Nix-toolchain campaign at signed revision 888e78a selected the five PubSub::transition candidates. Four whole-function replacements were unviable because they attempted invalid BehaviorActed construction; the topic-equality inversion compiled and failed the existing publication unit test. The strict gate accepted 1 viable / 5 total, with no survivor or timeout. Since that runner stopped after the unit failure, a separate isolated-worktree counterfactual changed only publication's topic comparison from == to != and ran the new independent property alone. It failed and shrunk to two commands: subscribe to topic 0, then publish to topic 0; the actor incorrectly returned NoSubscribers. The temporary edit and worktree were removed. This proves the independent oracle's topic-selection sensitivity, not the publication clone-loop or transport settlement law.

A07 actor mutation evidence: health observation versions

Classification: deliberate Bombay component-correlation and version-commit policy. A health observation updates only its selected component. Older evidence returns a stale error with its owned evidence; equal-version conflicting evidence returns a conflict; equal-version identical evidence is idempotent. A removal tombstone cannot be undone by an older observation.

The Nix-toolchain campaign selected all seven candidates in Health<A, K, Route>::commit at revision ab0d65f. The actor baseline and mutated actor and testkit suites passed or failed as expected. Every candidate compiled, then a named health test failed; the relevant tests were stale_and_conflicting_evidence_preserve_committed_state and tombstone_rejects_resurrection_and_report_aggregates_worst_status. The strict gate accepted 7 viable / 7 total, with no survivor or timeout. Reproduce the selection with cargo mutants --package bombay-behavior-actors --test-package bombay-behavior-actors --test-package bombay-behavior-testkit --test-tool nextest --no-shuffle --minimum-test-timeout 180 -f crates/actors/src/operations/health.rs -F 'Health<A, K, Route>::commit'. This is one operation-law slice, not an actor-wide mutation verdict.

A20 ledger entry: stable-proxy activation correlation

Evidence layerCurrent witness and limit
Focused transition and custodyproxy_command_recovery::equal_worker_values_and_endpoints_do_not_share_activation_authority checks every effect lane, unchanged phase, exact diagnostic return, admission by the original owner, and admission of the target's own activation.
Independent trace and compositionstable_proxy_shutdown_model explores activation, return, stop, and shutdown order; stable_proxy_owner_composition checks owner projection. These models do not themselves forge inconsistent worker and activation evidence.
Invalid constructionActivationPermit is affine and has a compile-fail duplication example; WorkerActivation has private fields and constructors that couple worker and activation evidence. The application cannot synthesize the inconsistent pair required by the surviving pre-edit && to `
CounterfactualFour of five pre-edit guard mutants were caught. The && to `

A20 ledger entry: FIFO completion child correlation

Evidence layerCurrent witness and limit
Focused transitionfifo_pool::delivery_and_completion_orders_complete_once places completion before and after the assignment receipt, then wraps an authorized completion with a foreign child ID. It checks no customer completion, one diagnostic, and later return of the still-assigned job during shutdown.
Independent tracefifo_pool::correlation::completed_work_advances_and_wraps_worker_selection checks completed work and worker selection across roles. The FIFO model and fuzz targets cover broader ordering; this mutation slice does not certify them.
Composition and invalid constructionThe completion authority is issued only from an assignment, but a ChildReport can carry a different creator-local child ID. The pool must check both. This is an aggregate ingress decision, not a wrapper-order transformation.
Ownership limitThe public FifoDiagnostic is intentionally opaque. The test checks diagnostic cardinality and that shutdown returns the still-assigned job, but it cannot inspect the exact foreign completion inside the terminal diagnostic. That custody seam remains for A17/A20.
CounterfactualAll three guard mutants at fifo_pool/mod.rs:276 built and were caught; viable selection and detection are recorded separately.

A20 ledger entry: keyed binding expectations

Evidence layerCurrent witness and limit
Focused transitionkeyed_pool::compile::keyed_construction_and_commands_need_only_domain_types exercises absent, exact, stale, same-role, cross-role, and removed bindings with distinct request IDs and generation values.
Independent traceThe test compares placement to a separate account directory; keyed pool assignment and lifecycle tests and keyed fuzz targets cover other transitions, not every binding counterfactual.
Composition and invalid constructionBindingExpectation is an exhaustive absent-or-exact sum; stale rejection returns the complete command and current generation. This is an aggregate binding decision, not a wrapper-order transformation.
CounterfactualBoth selected guard inversions in keyed_pool/mod.rs built and were caught by the binding integration test. The remaining keyed aggregate laws still need mutation slices.

A20 ledger entry: dynamic cancellation authority

Evidence layerCurrent witness and limit
Focused transition and custodydynamic::accepted_start_cancellation_retires_before_fresh_key_reuse checks current cancellation, returned authority and submission, exact retirement before key reuse, and the old authority's stale reply after reuse. It checks all send lanes and the continuing verdict for replayed and stale cancellation.
Independent traceDynamic cancellation and shutdown fuzz targets explore orderings. The focused integration trace has concrete expected replies but is not an independent state model.
Composition and invalid constructionCancelAuthority<Key> carries the key and operation; the actor compares it with the entry's current operation. This is a keyed aggregate decision, not a wrapper-order law. The authority is returned by start or replacement receipt and retained in cancellation replies.
CounterfactualInverting != to == built and failed four dynamic integration tests. Replacing != with > in an isolated worktree left current-token cancellation intact but made the old token after same-key reuse pass; the focused test failed at the stale assertion. These checks do not certify all dynamic entry phases.

A20 ledger entry: fixed replacement correlation

Evidence layerCurrent witness and limit
Focused transition and custodyfixed_supervisor_initialization::replacement_rejects_an_outcome_for_another_predecessor checks the complete foreign outcome returned through the diagnostic path. Valid receipt and coordinated-restart tests check a matching outcome waits for the independent predecessor stop.
Independent tracefixed_supervisor_initialization explores 90 lawful replacement arrival orders across recovery strategies. This is a local typed interpreter trace, not the downstream host required by A17.
Composition and invalid constructionThe outcome and pending replacement each carry exact predecessor evidence; the guard compares those values after the input settlement advanced to outcome-pending. A foreign predecessor can be reported by a runtime, so this is an aggregate ingress check rather than a static invalid-construction case.
CounterfactualGuard-true, guard-false, and equality-inversion mutants at recovery/mod.rs:1876 all built and were caught by fixed-supervision integration tests. This slice does not cover scheduling, policy selection, or terminal retirement.

A20 ledger entries: catalogue admission laws

LawFocused transition and broader witnessBoundary and counterfactual limit
Registry stale unbindThe registry unit test returns the stale recipient and keeps its binding; discovery model tests cover broader bind/lookup sequences.Recipient equality is a runtime command condition, not a compile-denial capability. One comparison inversion was caught; snapshot ordering is outside this slice.
Child creation ID and kindcreation_resolution_requires_matching_id_and_kind_independently returns each single-component mismatch with exact expected values and then accepts the lawful birth. The surrounding shutdown plan exercises nested event paths.Runtime reports can carry mismatched typed facts. The `
Configuration version conflictstale_and_conflicting_candidates_return_ownership_atomically checks stale version and same-version value conflict; catalogue models cover update sequences.This is a runtime version decision. The same-version comparison inversion was caught; no downstream persistence claim is made.
One-shot timer admissionThe one-shot unit trace checks initialization scheduling, matching generation, and exact-once firing; timing composition tests check wrapper use.A timer ID or generation mismatch is a typed runtime input. Four guard mutants built and failed the focused test; broader periodic and deadline laws are separate.
Barrier duplicate arrivalThe barrier unit trace checks exact membership and arrival-order release; workflow invariant tests cover reusable generations.A repeat arrival is an ordinary command rejection. One equality inversion was caught; it does not certify the future/stale-generation branches.

A20 pre-edit acknowledgement model law

Classification: deliberate Bombay participant-correlation policy. Begin normalizes declaration order; each declared participant can acknowledge once; the final acknowledgement completes; cancellation succeeds only while pending. Unknown, duplicate, unexpected, completed, and cancelled operations each return the exact rejected command or participant through the one reply lane, without changing the retained lifecycle. Terminal records remain distinct. The existing property checks begin/acknowledge in two separate batches and never emits Cancel, so it cannot prove the cancellation or interleaving law. The test-only replacement will generate mixed operations and varied reply recipients, compare every ordered reply and complete outcome, the full record order and current participant state, empty creations, and continuing verdict after every step. Its independent pending model retains original declaration and accepted participants, then derives remaining participants; terminal states discard those lists. It does not perform the actor's in-place removal. The existing concrete actor and Actions products remain the lower-order contracts. No production symbol, state, effect, runtime port, wrapper, or public spelling changes. Pre-edit control phases Pending/Completed/Cancelled, subordinate error/outcome alternatives, transition branches, production lines/modules, and public spellings stay fixed. Every retained model value is needed for a future acceptance, duplicate, or exact-order decision. No arrival-history residue is added to production; the model's accepted order is observable and therefore lawful. No repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax is proposed. Cross-check: actor transition algebra and the routing correlation catalogue. Disposition: pass for the test-only model before implementation.

The focused correlation suite passed all three cases in the Nix toolchain. The previous no-op reply-actor macro was deleted; both model routes use the existing concrete MessageProtocol. The new generated trace mixes Begin, Acknowledge, and Cancel, and a deterministic trace reaches unknown, unexpected, duplicate, completed, and cancelled replies. Every turn checks the exact reply recipient/outcome, all current records and order, empty creations, and Continue. In a disposable Behavior worktree, a one-line counterfactual changed only a repeat-cancellation reply from Cancelled to Completed. Both tests failed for that exact outcome; the generated trace shrunk to Begin, Cancel, Cancel on one key. The mutation and worktree were removed. This proves the new oracle detects wrong terminal rejection classification, not every acknowledgement defect. Test source changed +298/-119/net +179 physical lines; production +0/-0, public API +0/-0, control states, subordinate alternatives, transition branches, and modules are unchanged. The surviving model alternatives own exactly their future-needed current values; no arrival-history, repeated-cause, false cardinality, nested-authority, semantic-boolean, or positional-syntax residue remains. The actor transition and routing correlation contracts were cross-checked. Disposition: pass for this test-only evidence batch; A20 remains open. The pure trace does not prove host delivery admission or a wrapper-order interaction, and its isolated counterfactual covers one terminal branch only.

A20 pre-edit correlation reply custody

Classification: deliberate Bombay keyed-correlation policy. Begin retains one exact reply recipient while pending. A matching Resolve or Cancel emits one terminal result to that recipient, then removes its authority; a later reply is rejected with complete key/value ownership. The current generated property uses the same reply route for every Begin and checks only the first send's payload on successful terminal transitions. It cannot detect a wrong destination, duplicate send, creation, or stop verdict. The test-only candidate varies reply recipients, retains their address in the independent model only while pending, and compares all successful action lanes and the exact retained state after every operation. Existing CorrelatorError cases already check the owned rejected values. No production state, transition, effect, interpreter operation, wrapper, public spelling, module, or line changes are proposed. Control phases Pending/Completed/Cancelled and every subordinate alternative remain fixed; the pending reply address is the exact future-needed current value. The residue scan finds no proposed arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax. Cross-check: actor transition algebra and routing correlation law. Disposition: pass for the test-only model before implementation.

The focused three-case correlation suite passes after the property varies reply addresses for each Begin. Successful Begin asserts empty sends and creations plus Continue; matching Resolve and Cancel each assert exactly one send to the retained recipient, the complete result, empty creations, and Continue. The record comparison now checks the retained pending recipient alongside its key and phase. Every existing rejection still checks its exact returned key, value, or submitted reply route. Test source changed +26/-10/net +16 physical lines (393 → 409); production +0/-0, public types, control states, subordinate alternatives, transition branches, and modules are unchanged. The pending recipient is discarded from the model upon terminal settlement, matching the current-value law. No history, repeated cause, false cardinality, nested authority, semantic boolean, or positional consumer syntax was added. The actor transition and correlation laws were cross-checked. Disposition: pass for this test-only batch; a dedicated route mutation and real interpreter delivery remain outside it.

A20 ledger entries: machine, stash, and cache

LawFocused transition and broader witnessBoundary and counterfactual limit
Machine phase replayalgebra::fsm_is_receive_plus_become_policy observes phase change and held-message replay; fsm_properties separately exercises self-Goto, generated sequences, and rollback.Inverting phase equality built and failed the changed-phase algebra test. The self-Goto oracle is separate; this mutation slice does not test every error rollback branch.
Stash FIFO releasealgebra::stash_release_delivers_the_trigger_then_drains_the_held_fifo checks trigger-first delivery and held FIFO order; stash_properties covers generated hold/release sequences.Replacing drain_into with a no-op built and failed the algebra test. The statically infallible inner behavior is the applicable compile-time constraint; runtime route choices remain typed.
Cache replacement and evictionCache unit tests check recency, full-capacity eviction, and complete replacement/removal custody; catalogue_invariants compares generated operations with an independent ordered-entry model.Zero capacity is rejected at construction. Both capacity-condition mutations built and failed cache tests; this slice does not certify other persistence mechanisms.

A20 ledger entry: bounded-buffer capacity and ownership

Evidence layerCurrent witness and limit
Focused transitionrouting/buffer.rs tests zero capacity, FIFO release and empty outcomes, and every overflow policy with distinct values.
Independent tracebehavior-testkit/tests/routing_invariants.rs::buffer_preserves_fifo_and_returns_every_unaccepted_value compares retained FIFO values and returned custody after each generated command; it does not claim transport admission.
CompositionThe buffer is a standalone Behavior whose destination lanes are concrete DeliveryRoutes. There is no wrapper-order law for its capacity decision; route typing is checked separately in composition/delivery_route.rs.
Invalid construction and boundariesBufferConfiguration::new(0, ..) returns ZeroCapacity; a runtime numeric capacity is validated at construction. The full-queue tests distinguish Reject, DropNewest, and DropOldest ownership.
CounterfactualThe five guard/operator mutants in the A07 slice were all caught by actor buffer tests. This evidence covers this capacity branch only.

A20 ledger entry: lease holder and generation correlation

Evidence layerCurrent witness and limit
Focused transitiontime::lease::tests::acquire_renew_release_and_stale_elapsed_are_generation_safe and wrong_holder_and_matching_expiry_are_distinct check renewal, wrong-holder rejection, stale expiry, release, and continued state.
Independent tracetiming_invariants::lease_matches_exclusive_generation_ownership_after_every_event compares each generated outcome, scheduled generation, and held/vacant state against its own model; it caught the false stale-generation guard.
Compositionrecursive_reply_protocols and exact-reply template tests prove typed reply routes; this mutation slice does not establish a separate wrapper-order law for Lease.
Invalid construction and boundariesHolder and generation are concrete typed inputs. generation_exhaustion_is_terminal_and_never_wraps checks the upper sequence boundary; the model's generated sequence stays below it.
CounterfactualSeven viable successor mutations were caught; one replacement could not compile because TimerGeneration has no Default. Other lease transition branches remain outside this campaign.

A20 ledger entry: termination observation and propagation

Evidence layerCurrent witness and limit
Focused transition and custodyLogical-monitor unit tests check matching reaction actions, duplicate rejection, exact foreign-report return, and continued user delegation. Established-monitor integration tests check requested, observing, cancelled, and observed phases with exact observation IDs; the independent model also covers rejection. The propagation peer regression checks foreign return before selected-peer publication and stop.
Independent traceexact_termination_model compares generated exact-report phases and reaction count but does not inspect every action lane. terminal_outcome_sequences independently predicts selected-child acceptance, foreign return, discharge, publication, and later rejection; since f0dce34 it also checks initialization and every effect lane on successful steps. It does not model PeerTermination.
Composition and invalid constructionThe exact monitor composes inside StopOnShutdown, and the logical monitor appears in the universal-layer tests. No two-order wrapper proof is claimed for propagation. A child target requires a typed creation ID and protocol occurrence; a foreign report is a runtime input returned through the typed error.
CounterfactualEight viable monitor mutations were caught and two were unviable. The propagation campaign exposed an unconditional-peer-acceptance survivor; its isolated post-regression rerun was caught by the new focused test. The two campaign reports retain their separate baselines and verdicts.

A20 ledger entry: work admission and availability

Evidence layerCurrent witness and limit
Focused transition and custodyrouting::work_queue unit tests cover FIFO worker selection, queued dispatch, and zero-capacity rejection. The newer independent property also checks every emitted assignment and outcome, recipient, empty creation lane, and continuing verdict.
Independent tracerouting_invariants::work_queue_matches_two_coupled_fifo_capabilities tracks waiting work and available workers in separate deques, with unique reply recipients and a non-Clone work payload. It checks the complete observable state after every generated operation. It does not claim transport admission.
Composition and boundariesExact reply-route template tests cover logical and established customer routes. The property generates capacities including zero and repeated worker notices and withdrawals; it does not check downstream worker execution.
CounterfactualTwo viable guard mutants failed actor unit tests; two whole-function replacements were unviable. The strengthened independent property passed after this campaign, so the original verdict is not attributed to it.

A20 ledger entry: keyed publication membership

Evidence layerCurrent witness and limit
Focused transition and custodydiscovery::pub_sub unit tests check first subscription order, duplicate suppression, and publication rejection for known empty and unknown topics. The independent property checks the exact returned topic, recipient, and original publication allocation.
Independent tracecatalogue_invariants::pub_sub_preserves_topic_membership_and_rejected_publications tracks membership in a map plus introduction order, then compares every current topic, recipient order, successful action lane, and rejection after generated commands. Each publication has a distinct owned string. It does not interpret transport admission.
Composition and boundariesExact reply template tests exercise established publication routes. The property explores absent topics, empty retained topics, duplicate recipients, and re-subscription; it does not prove scheduling or downstream delivery. Topic/member capacity and topic retirement still need laws as recorded in atomic-actor-other-templates.md.
CounterfactualAll six selected membership mutants compiled and failed named unit tests. The separate topic-selection campaign caught one viable equality inversion and had four unviable replacements. An isolated rerun of that inversion against only the independent property failed with a two-command counterexample. Publication clone-loop and transport settlement evidence remain open.

A20 ledger entry: health observation versions

Evidence layerCurrent witness and limit
Focused transition and custodyThe two operations::health tests check component selection, stale and equal-version conflicts, idempotence, tombstone retention, and report aggregation. Error variants retain the rejected component and evidence.
Independent tracebehavior-testkit/tests/catalogue_invariants.rs::health_tombstones_and_versions_match_an_independent_map compares generated health operations and complete rejected evidence with an independent ordered component map. It does not interpret host delivery admission.
Composition and boundariesThe health actor returns its report through a typed route. Version equality and ordering are explicit in the pure transition; the focused test includes a removed component and a later older observation. No wrapper-order claim is made for this standalone actor.
CounterfactualAll seven selected Health::commit mutations compiled and failed named health tests. The strict gate accepted 7 viable / 7 total; other health methods remain outside this slice.

A20 ledger entries: ordered routing and workflow

The next A20 test-only experiment targets the circuit breaker's deliberate single-flight and reset policy. A model built from the documented public contract owns a free slot with consecutive failures, one accepted attempt, a cooling generation, or a single trial. It predicts every reply recipient and outcome, timer request, next phase, empty creation lane, and continuation after each generated command. Successful admission must retain the same attempt until its matching completion; unrelated completions return the exact command; stale timer evidence changes nothing. The existing focused breaker tests and typed TimerElapsed input are lower-order witnesses. No production type, state, transition, or interpreter port is proposed. The pre-edit aggregate control sum is Closed/Idle, Closed/Awaiting, Open, Probing/Available, Probing/Awaiting, and Exhausted; the test adds no alternative to it. The model's phase is an independent expected-value oracle, not another production transition authority. The source has one aggregate module and its existing branches remain unchanged. A mutation of the reset-generation guard must fail this oracle before the test is retained. Cross-checks are the actor transition algebra and normalized routing catalogue law. Disposition: pass for the test design, pending the counterfactual and measurements.

The retained circuit_breaker_model compares generated command sequences with an independently named single-flight/cooling/trial oracle, plus a deterministic open/reopen trace. Each successful step compares ordered reply recipients and complete outcomes, exact reset requests, phase and owned attempt, empty creation lane, and continuing verdict; each invalid completion checks its exact returned command. The generated instructions include current and foreign completions, matching/stale timer generations, and a foreign timer ID. Attempt-number and generation exhaustion remain in the focused unit tests, since generated traces cannot approach u64::MAX. This is a pure transition proof; it does not establish timer scheduling or delivery by a real runtime. Both tests passed in debug and optimized Nix builds.

The isolated one-line counterfactual inverted the timer-generation equality guard. Both tests failed; the generated oracle shrank to Admit, Fail, Admit, Fail, ElapsedCurrent, where the actual phase remained open instead of offering one trial. The temporary mutation and worktree were removed. This proves the model detects incorrect matching-reset admission, not every possible circuit-breaker defect. The test-only batch changes production +0/-0/net 0, tests +419/-0/net +419, public API +0/-0 types, production lines 404 → 404, production modules 1 → 1, and production transition branches unchanged. The control sum remains Closed/Idle, Closed/Awaiting, Open, Probing/Available, Probing/Awaiting, Exhausted; its owned values and future decisions remain those stated above. The residue scan found no production arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax. The transition algebra and routing catalogue record were cross-checked. Disposition: pass for this test-only evidence batch; A20 remains open. The complete nix flake check -L passed all ten declared checks at signed commit ad4d198, including optimized Nextest with 826 passing cases, release tests, doctests, Clippy, package, documentation, formatting, dependency-audit, and dependency-policy gates.

LawFocused transition and independent traceRemaining proof boundary
Sequencer gap releaserouting::sequencer tests missing, stale, duplicate, and maximum positions. catalogue_models::sequencer_matches_an_independent_gap_map_after_every_offer compares deliveries, outcomes, state, and empty creation lane after each generated offer.Generated positions stay below exhaustion. The maximum-position unit test covers that separate boundary; no sequencer mutation slice is recorded.
Deduplicator retentionrouting::deduplicator tests duplicate custody, eviction, and zero capacity. catalogue_models::deduplicator_matches_an_independent_fifo_window_after_every_delivery compares both send lanes and retained keys, and checks that the exact boxed value allocation travels through admission or rejection.The model varies positive capacities; zero capacity is a constructor rejection in the focused test. Transport admission and a dedicated mutation slice remain unproved.
Order-gate watermarkcatalogue_models::order_gate_matches_an_independent_watermark_map_after_every_operation compares ordered releases, duplicate and stale-open outcomes, watermark, held count, and empty creation lane after each generated operation.The generated trace does not prove a runtime delivery receipt or a dedicated guard mutation slice.
Priority selectionrouting::priority_queue tests stable priority/FIFO ties and full/empty outcomes. routing_invariants::priority_queue_matches_stable_max_priority_selection compares an independent ordered list after each offer or release, including exact delivery and reply recipients, reply depth, empty creation lane, and continuing verdict. An isolated Released.remaining = queued.len() + 1 counterfactual compiled and failed at the new remaining-depth assertion on a one-offer, one-release trace.The generated priorities cover 0–7 and positive capacities below eight; exhaustion and real host admission are outside this property. The recorded counterfactual covers the release-depth branch, not every routing branch.
Rate admissionrouting::rate_limiter tests accepted/rejected ownership and saturating refill. routing_invariants::rate_limiter_matches_saturating_token_arithmetic compares capacity, available tokens, rejection reasons and returned value, and admitted delivery after each generated operation.Its generated path constructs positive token costs and capacities; no host admission or dedicated mutation slice is recorded.
Round-robin membership cursorrouting::router tests cursor repair after removal. routing_invariants::round_robin_keeps_the_same_next_recipient_across_membership_edits tracks an independent member list and next recipient through generated edits and routes.The pure trace does not prove transport admission.
Consistent-hash membership stabilityrouting::router tests one three-member removal over 128 keys. routing_invariants::consistent_hash_membership_edits_preserve_unaffected_key_owners checks complete actions, Unknown admission, varying tokens and keys, aligned evidence, addition, and removal in 128 generated cases. An isolated no-removal mutant failed at the exact surviving member token, shrinking to tokens [0,1,2,3].The relational property does not independently calculate every ring point or prove host delivery admission; the focused actor test covers same-version conflict but stale token evidence still needs a direct witness.
Least-loaded evidencerouting::router tests unknown, stale, conflicting, tied, and newly lower evidence. routing_invariants::least_loaded_matches_versioned_membership_and_selection models member order and latest evidence after mixed add, remove, observe, and route operations; a deterministic trace covers re-addition.An isolated max-load selection counterfactual failed both new tests; pure routing still does not prove host delivery admission or the other policy families.
Rendezvous member stabilityrouting::router tests one keyed route, conflicting token, and exact stale-version return. routing_invariants::rendezvous_membership_edits_only_move_keys_to_or_from_the_changed_member checks exact route actions, token evidence, membership edits, and order-independent ownership for 128 generated distinct-token cases. An isolated index-dependent score counterfactual failed at the permutation assertion with a minimal [0,1,2,3] token set.This relational law does not independently calculate each score or prove host delivery and every tie case.
Latch releaseworkflow::latch tests threshold order and zero-count startup. workflow_invariants::latch_releases_each_accepted_route_exactly_once compares an independent waiting list, release phase, and exact recipient order through generated arrivals.The property does not interpret delivery admission or record a dedicated mutation slice.
Dependency workflowworkflow_invariants::workflow_matches_an_independent_dependency_run tracks step and run phases across start, completion, failure, and cancellation, including invalid early completion and failure.The focused property and workflow unit tests do not provide a real interpreter trace or dedicated mutation slice for every branch.

A20 pre-edit consistent-hash membership law

Classification: deliberate Bombay ring-routing policy. With a fixed key hash, stable member tokens, and a positive replica count, adding an Unknown member changes no existing assignment; accepting its token can move a key only to that member. Removing a member can change only keys it owned. These are relational consequences of the stated clockwise ring selection law and do not require a test to duplicate the point-mixing function. A generated test will vary four distinct tokens and extra keys, compare complete route and observation Actions, member order and token evidence, then check the two before/after ownership relations. The focused three-member removal test and the typed MemberTokenObservation are the lower-order witnesses. An isolated mutation that leaves removed token evidence in the policy or changes the selected eligible point must fail the generated law before retention.

The Router's one ordered membership control state, Unknown/Observed token evidence, three hash rejections, transition branches, modules, production lines, and public spellings remain unchanged. Current member order and each latest token/version are the only values needed for later selection and stale/conflict decisions. The proposed test adds no actor state, arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or structural caller syntax. Cross-checks are the actor transition algebra and normalized routing catalogue law. Disposition: pass for the test model, pending the generated trace and counterfactual.

Post-edit, all ten routing invariant tests pass in debug and optimized Nix builds. The new consistent-hash property checks every successful action lane and continuation, exact keyed deliveries, member order and token evidence, then the before/after key-owner relations. A shared typed route assertion now serves the ring and rendezvous properties, deleting their duplicate action check without adding a production bound. In an isolated Behavior worktree with its own Cargo target, deleting only HashMembership::removed made the new property fail at the exact survivor-token assertion; proptest shrank to tokens = [0,1,2,3] with no extra keys. The mutant and worktree were removed. This counterfactual proves detection of missing token-position repair, not the ring mixer or runtime admission.

The test-only batch changes production +0/-0/net 0, tests +98/-16/net +82, and public API +0/-0 types; the routing invariant file is 790 to 872 physical lines. Router control, hash evidence alternatives, rejections, branches, production modules, and all future-needed member and token values remain unchanged. The residue scan and law-document cross-check above found no new production history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax. Disposition: pass for this evidence batch; A20 remains open for other laws.

A20 pre-edit hash-token version law

Classification: deliberate Bombay evidence policy, shared by consistent and rendezvous selection. Once a member has Observed(version, token), an older observation must return its exact owned value with Stale and leave the committed evidence unchanged. The same version/token is idempotent, the same version with a different token is a conflict, and a newer version replaces the current token. The existing rendezvous example covers conflict only. A focused pure Router test will prove stale ownership, idempotence, newer acceptance, all action lanes, and evidence state. An isolated inversion of the version ordering guard must fail the stale or newer assertion before retention.

No production type, branch, module, public spelling, or state alternative is proposed. Router's one ordered membership list and each current token/version remain exactly the values used by later selection and rejection. The test adds no arrival-history state, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax. Cross-checks are the actor transition algebra and normalized routing catalogue law. Disposition: pass for the test model, pending the focused witness and counterfactual.

Post-edit, the focused router test passed in debug and optimized Nix builds. It checks the exact stale observation in both returned policy fields, no evidence mutation, idempotent same-version replay, a newer accepted token, and empty send/create lanes with continuation. The existing conflicting-token test now also checks the exact returned observation in both fields. In a separate Behavior worktree and Cargo target, inverting only the hash evidence version guard made the new test fail at the stale-return assertion. The mutant and worktree were removed. This counterfactual tests ordering of version admission; it does not prove the hash score or host delivery.

The actor source test section changes +84/-14/net +70 physical lines; production Rust, public types, control states, evidence alternatives, transition branches, and modules stay unchanged. The current member order and latest version/token remain the only future-needed values. No arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or structural caller syntax was introduced. The actor transition and normalized routing laws were cross-checked. Disposition: pass for this focused evidence batch; A20 remains open elsewhere.

A20 pre-edit least-loaded evidence law

Classification: deliberate Bombay routing policy. A member is ineligible until it has versioned load evidence; the least load wins and declaration order breaks ties. Unknown, stale, and same-version conflicting observations return the exact evidence without changing membership or load. Removal retires a member's evidence, so re-addition begins unknown. A source-only unit test checks selected examples but no generated trace combines all of these operations. The test-only candidate uses an ordered list of members with optional latest (version, load) evidence and independently scans for the first minimum, rather than calling the strategy's selection logic. Mixed generated and deterministic traces will compare complete delivery or rejection, every action lane, member order, and evidence after every step. Existing Router/LeastLoaded types and actor unit tests are the lower-order contracts. No production type, trait, state, effect, wrapper, interpreter port, or public spelling changes. Baseline actor control remains one router with an ordered membership list; subordinate evidence is Unknown or Observed. Its latest version/load pair and membership order are the exact future-needed values. Production branches, lines, and modules remain fixed. The residue scan finds no proposed arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional consumer syntax. Cross-check: actor transition algebra and normalized routing catalogue law. Disposition: pass for this test-only model before implementation.

The retained independent model uses an ordered member list and each member's optional latest version/load reading. It predicts the first minimum, exact reply or returned value, all effect lanes, and membership and reading state after every operation. The deterministic trace covers tied loads, stale and conflicting observations, removal, and re-addition; 384 generated traces mix those operations. The seven focused routing invariant tests passed after a clean Nix development build; both new tests also passed in the optimized Nix build. An isolated one-line counterfactual changed the selection from minimum to maximum. Both new tests failed for the intended recipient-selection law, and the generated trace shrank to two observed members followed by one route. The counterfactual worktree was removed.

The isolated worktree temporarily shared the main checkout's Cargo target directory. A later main-checkout test linked its mutated artifact and failed; that failure is excluded from the baseline evidence. Cleaning both affected packages and rebuilding the unchanged main actor source restored the seven passing tests. Future worktree counterfactuals need separate Cargo targets. This test-only batch changes production +0/-0/net 0, tests +235/-1/net +234, and public API +0/-0 types; the test file is 414 → 648 lines. Production router.rs stays at 1,311 physical lines and its modules, branches, and public spellings are unchanged. Router control remains an ordered membership list with each member Unknown or Observed; the optional latest reading and order are precisely the future-needed values. The test model adds no production state or nested transition authority. The residue scan found no arrival history, repeated cause, false cardinality, semantic boolean, or structural caller syntax. The actor transition algebra and normalized routing catalogue law were cross-checked. Disposition: pass for this evidence batch; A20 remains open for the rest of the ledger.

A20 ledger entries: catalogue versioning and membership

Next A20 routing candidate, before test changes: the Rendezvous policy's stable member token is an explicit versioned fact, and adding an eligible member can only keep an existing key assignment or move that key to the new member. Removing a nonselected member cannot change an assignment. With distinct tokens, reversing declaration order must preserve each key's owner because the score depends on key and token, with no tie to break. This is a deliberate Bombay highest-score policy, not an actor-model requirement. The existing rendezvous_hash_is_deterministic_and_rejects_conflicting_tokens unit test checks only one key before a conflicting observation; it does not exercise membership edits across a key set. A generated relational trace will compare the complete route Actions, member order, token evidence, permutation ownership, and the before/after owner of each key through add and removal without copying the hash mixer. The existing router, MemberTokenObservation, and RoutingStrategy are the lower-order contracts. No production state, type, effect lane, public spelling, interpreter port, or policy changes. Router control remains an ordered member list; the hash policy's only subordinate alternatives are Unknown and Observed(version, token). Order and latest token are precisely the future-needed values. Production branches, lines, and modules remain unchanged. The proposed property introduces no arrival history, repeated cause, false cardinality, nested authority, semantic boolean, or positional caller syntax. Cross-check: actor transition algebra and normalized routing catalogue law. Disposition: pass for the test design, pending the counterfactual and measurements.

The retained test compares key owners before and after adding an unknown member, accepting its token, reversing the fully observed membership order, and removing one member. Every route checks the exact keyed payload and recipient, empty creation lane, and continuation; membership operations check all lanes and the policy's current evidence. The focused property passed in debug and optimized Nix builds. A disposable worktree with a separate Cargo target changed the Rendezvous score to depend on the member index. The property failed at the order-independence assertion and shrank to distinct tokens [0, 1, 2, 3] with no extra keys. The worktree and its generated seed were removed. This proves the property rejects index-dependent selection; the relation alone does not certify the exact mixer or every token branch.

This test-only batch changes production +0/-0/net 0, tests +145/-5/net +140, public API +0/-0 types, and the test file 648 → 788 physical lines. Router production remains 1,311 lines, with unchanged branches, modules, public spellings, and aggregate control state. The surviving subordinate Unknown and Observed alternatives still own the same latest version/token needed for future routing and rejection. The residue scan found no production arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional consumer syntax. The actor transition and normalized routing laws were cross-checked. Disposition: pass for the test-only evidence batch; A20 remains open for other catalogue and runtime laws.

LawFocused transition and independent traceRemaining proof boundary
Configuration versionoperations::configuration tests stale and equal-version conflicting candidates with complete value return. catalogue_invariants::configuration_is_a_monotonic_atomic_register compares each generated proposal with an independent optional version/value register, including idempotent equality and every action lane.The recorded equality mutant covers one guard only; persistence and host delivery do not follow from this pure actor trace.
Readiness evidencecatalogue_invariants::readiness_matches_per_dependency_version_registers compares three independent version/status slots after generated known and unknown observations, including stale and equal-version conflicts with returned evidence.The generated range cannot reach numeric version exhaustion, and no dedicated readiness mutation slice is recorded.
Registry identitydiscovery::registry tests atomic stale unbind. catalogue_invariants::registry_matches_atomic_compare_and_remove_bindings compares a separate ordered binding list and exact bind, unbind, and lookup outcomes after generated commands.The existing inversion covers exact-recipient comparison only; snapshot ordering and host delivery have no dedicated counterfactual here.
Topic membershipcatalogue_invariants::topic_is_an_ordered_idempotent_membership_snapshot models first subscription order, duplicate subscription, unsubscribe, and publication to every current recipient or exact empty-topic rejection.This standalone topic law differs from keyed PubSub membership; no topic-specific mutation slice or host admission is claimed.

Next A20 test-only boundary hypothesis, before edit: readiness version evidence is ordered by the full u64 domain. At the maximum version, lower evidence is stale, equal identical evidence is idempotent, and equal contradictory evidence is rejected with the exact input; no arithmetic or wraparound manufactures a newer observation. This is Bombay's version policy, not an actor-model law. The existing independent three-dependency register model already checks the complete state and action product after each generated command but samples only small versions. Add u64::MAX - 1 and u64::MAX to that model's input domain, retaining its own comparison equation and exact error checks. No production state, type, lane, branch, public spelling, module, or line changes. The root readiness state remains a fixed ordered list of Unknown or Observed(version,status); each observed pair is exactly the current value needed by the next comparison and query. No arrival-history, repeated cause, false cardinality, nested authority, semantic boolean, or structural syntax is introduced. Cross-checks: actor transition law and normalized operations catalogue. Disposition: pass for the test design, pending the run.

The widened register model passed in debug and optimized profiles. Each generated trace still checks exact rejection data, the complete empty action product on acceptance, and all three dependency slots after every command. The change is test-only (+0/-0 production lines, zero states, branches, modules, and public spellings); the current evidence pair and fixed ordered membership remain the only future-needed values. The residue scan and law cross-check above remain unchanged. Disposition: pass for the boundary evidence, with A20 still open for other catalogue and runtime laws.

A disposable worktree made readiness treat u64::MAX as stale even after version zero. The widened independent model failed and shrank to two commands: commit (dependency 1, version 0, Ready), then offer the same dependency at u64::MAX; the model required acceptance while the mutant returned the exact wrong Stale error. This counterfactual demonstrates that the new boundary input is exercised and the oracle rejects the bad ordering. The mutant and its generated seed were removed; production remains unchanged.

The remaining catalogue laws need equally specific entries, so A20 remains open.

A20 Nix coverage measurement

The flake now provides nix run .#coverage -- --lcov --output-path target/coverage.lcov, using the pinned Rust toolchain, its LLVM tools, and Nix-provided cargo-llvm-cov. The default development shell also includes cargo-llvm-cov. A full --workspace --lib --tests --locked run passed after the A11 migration and produced target/coverage.lcov; the macro fixture integration tests ran too. Instrumented source-line observations were: core 1,584/1,834 (86.4%), actors 25,438/30,848 (82.5%), macros 727/899 (80.9%), testkit 70/73 (95.9%), and mutation gate 309/348 (88.8%). The actor files with the least measured execution among files of at least 30 instrumented lines include stable-proxy state (15/71), the shared send-product derivation (21/46), dynamic-supervisor event (21/43), dynamic-supervisor entry retirement (43/85), stable-proxy protocol (46/87), and delivery-route composition (81/149). Some generic code depends on which concrete products are instantiated, so these counts identify review targets, not necessarily missing runtime transitions. A20 remains open until the law ledger and counterfactuals cover the full catalogue.

Repair ledger: dependency resolution and mutation verdicts

Before production edits, the blockers are A02 and A05. The macro law is a derived Cargo/Rust naming contract: generated paths must name the actual extern crate for ordinary package declarations and explicit renames. An external consumer with both direct dependencies and the facade is the focused witness; its unrenamed #[behavior] and #[pool_worker] uses must compile, while the existing renamed and missing-dependency witnesses retain their outcomes. The smallest expected production change is in behavior-macros/src/lib.rs (roughly 10 lines), with a fixture manifest/source, its lockfile, and the fixture test harness. No public types are added or removed; generated behavior and actor products and the existing facade resolution are reused.

The mutation-gate law is deliberate Bombay verification policy: exactly one successful baseline and exactly one terminal, valid outcome for each discovered mutant identity are required before a coverage verdict. A report missing its baseline, duplicating an outcome, or reporting Failure must fail even if its function-level viability floor is met. Focused adversarial report tests will fail on the current gate before changing it. The expected production edit is mutants-gate/src/main.rs (roughly 45 lines); the report's own mutant name and existing function-floor products are reused. No public types are added or removed. Neither repair changes actor transitions or interpreter effects.

Initial cumulative scope includes this audit and its two index links: three changed documentation files. The macro fixture required its own package because Cargo rejects the same package under renamed and unrenamed keys in one manifest; the repair adds seven macro and gate files rather than the estimated five. This ledger will be updated with measured production/test/API deltas at the next checkpoint.

Repair batch result on codex/repository-quality-repairs

  • A02 complete. Both unrenamed direct package declarations compile the ordinary #[behavior] and #[pool_worker] expansions in an external consumer. The direct-plus-facade fixture now also uses a renamed direct actors dependency and exercises both entry points. Facade-only, renamed-facade, facade sibling example, and missing-dependency fixtures retain their outcomes. All four crate_resolution tests passed after the fixture lockfile was regenerated offline. A later Nix run exposed that the nested lockfile had selected four registry versions absent from Nix's vendored root lockfile. The nested indexmap, syn, toml_edit, and unicode-ident versions now match the root lock; all four macro consumer tests passed again under --offline --locked.
  • A04 complete. The adapter denial now supplies a current ChildDelivery and a compiling Recipient counterpart. The activation permit denial has the required generic bounds and a compiling single-transfer counterpart. The heterogeneous birth denial has the interpreter's real future signature; an isolated compiler probe produced E0277, and the same source compiled after adding the missing concrete child host. Filtered doctests passed.
  • A05 complete. The gate reads the cargo-mutants name field as candidate identity, requires exactly one successful baseline and one valid outcome per selected identity, rejects unknown or duplicate identities and malformed reports, and keeps function-level viability floors. Debug and release unit tests passed. Direct CLI probes returned exit 0 for a complete clean report and exit 1 for missing baseline, failed mutant, duplicate outcome, and an invalid Success mutant; emit-baseline produced the expected viability inventory.
  • A08 and A16 partially repaired. The facade sibling example is explicitly selected by the macro consumer gate. The root README now has current local links, package versions, and interpreter trait names. Its code example compiled as an external offline path-dependent consumer, and a repository test checks its local document targets. Published package verification and the remaining entry-point and historical-document review stay open.

Scope checkpoint after this batch: 15 changed files; production +87 / -67 / net +20 lines; tests, fixtures, and doctests +295 / -43 / net +252 lines; public API +0 / -0 types. These counts use line comparisons with inline test modules separated from production. The positive production delta is new verdict validation, not a code reduction. No actor aggregate control state, subordinate alternative, transition branch, module, or public spelling changed; the aggregate-drift checkpoint has the same before and after representation. The residue scan found no new arrival history, repeated cause, cardinality assumption, nested transition authority, semantic boolean, or positional user syntax in this batch. Its disposition is pass for these tooling and fixture repairs; it makes no claim about A01/A03 or the catalogue simplification candidates. Actor-transition and normalized atomic laws were cross-checked for scope, with no actor transition changed.

A03 pre-production projection law and failing caller

Classification: this is Bombay's derived static hosting requirement, not an actor-model transition law. A concrete send product must expose, in declared interpretation order, every protocol that one of its values can address logically. The type-level product must retain repeated occurrences. An InterpreterRequests<CustomerDelivery<P>> lane can address P logically even when a particular value selects its exact variant, so its projection contains one P. A DiagnosticAction<Recipient<P>, Diagnostic> can similarly target P; an established-only or terminal-only route adds none. A wrapper appends its inner requirements before its owned requirements, and transitive child requirements follow the actor's sends. This projection is evidence only; it cannot perform routing, allocation, or any Actions effect.

The pre-edit external consumer uses the public LogicalDeliveryProtocols::Protocols syntax. It requires InterpreterRequests<CustomerDelivery<CustomerProtocol>> to equal BirthProtocol<CustomerProtocol, NoBirthProtocols> and requires FifoRequests<NoSends, ...> to implement LogicalDeliveryProtocols. cargo check --offline failed for the two intended reasons: the first product is currently NoBirthProtocols, and the FIFO product has no implementation. An independent diagnostic caller required InterpreterRequests<DiagnosticAction<Recipient<DiagnosticProtocol>, ()>> to contain that protocol while its EstablishedRecipient counterpart remained empty. It failed only the logical-route assertion, confirming that the defect is the blanket empty request projection rather than the exact-route case. Focused assertions now live in behavior-testkit/tests/logical_host_requirements.rs. Before production edits, cargo test -p bombay-behavior-testkit --test logical_host_requirements --no-run fails on the customer request, logical diagnostic request, and both wrapper orders; the exact diagnostic counterpart remains the empty control case.

The existing lower-order pieces are LogicalDeliveryProtocols, BirthProtocolProduct::Append, SendLayer's inner-to-outer ordering, BirthNodeLogicalHosts, InterpreterRequests, the four atomic request products, and ProxyEffects. Customer delivery and diagnostic routing are already interpreted through typed request lanes. No interpreter action or acceptance contract needs to change. A candidate design would give request items a separately owned logical-protocol projection, then make InterpreterRequests<M> project M rather than always returning empty. It must prove two real nonempty request families, all five atomic families, transitive children, and two wrapper orders without mandatory placeholder inputs.

The selected public contract extends the existing InterpreterRequest seam with an associated logical-protocol product. Each request already owns its return continuation and possible recipient; a separate public trait would split one request law across two implementations. The caller writes the same InterpreterRequests<Request> syntax; only static LogicalHostRequirements::LogicalHosts evidence changes. Host-free schedule, observation, exact lifecycle, and parent-report requests select NoBirthProtocols. CustomerDelivery<P> selects P; diagnostic route capability selects logical P or empty. The request-product derivation appends authored field products in interpretation order; ProxyEffects does the same. Existing BirthProtocolProduct::Append, wrapper ordering, transitive birth projection, request interpretation, and all runtime ports are reused. No transition, rejection, effect, or custody value changes.

Pre-edit shape checkpoint: the five atomic actor control-state sums and their subordinate alternatives remain exactly as declared; this batch changes no state or result variant, transition branch, or source module. The affected implementation files currently total 6,619 physical lines across 11 files; the five atomic aggregate trees have 37 module declarations and 76 enum or interpreter-request declarations by source scan. Public type and trait names remain unchanged; one associated type is added to the existing request port. Every surviving alternative retains precisely its prior current values. The residue scan found no proposed arrival-history state, duplicate cause, cardinality assumption, nested transition authority, semantic boolean, or positional caller syntax. Cross-check docs/actor-transition-algebra.md, docs/behavior-layer-laws.md, docs/atomic-runtime-settlement.md, and the normalized atomic-family laws after the projection is compiled. Disposition is pass: the post-edit implementation files total 6,707 physical lines, net +88 for this type-level repair. Actor control states, subordinate alternatives, transition branches, and source modules remain unchanged; the same residue scan found no new historical state, duplicate cause, false cardinality, nested transition authority, semantic boolean, or positional caller syntax. The only public shape change is InterpreterRequest::LogicalProtocols; no new public type or trait name was added. The normalized actor laws and the transition and layer documents were cross-checked; the stale claim that every interpreter request is host-free was corrected in the core and composition documentation. Focused regressions assert exact logical customer and diagnostic projections, exact-route exclusion, two wrapper orders, and duplicate occurrence preservation. Real FIFO, keyed, fixed, dynamic, and stable-proxy behavior compositions compile with their expected protocol products or positions, including a transitive worker host. The full workspace gate passed 797/797 tests.

A01 creation-order policy before documentation repair

Agha et al., “A Foundation for Actor Computation,” section 3.1, separate fresh address allocation (newadr) from behavior initialization (initbeh). They do not prescribe Bombay's host commit, initialization-action settlement, or activation sequence. The contradictory orders in the two local documents are the pre-edit failing contract witness.

Bombay's selected policy is: reserve a fresh address without publishing a live endpoint; run the child's pure definition initialization; install the endpoint and commit the creator-local nonce binding only after that fold succeeds; then settle all initialization actions before ordinary ingress. Reservation failure returns the whole staged request. A pure initialization error returns the current child and exact error. An installation failure after a successful fold returns the current child and uninterpreted initialization actions. After commit, an effect rejection or interpreter fault belongs to the installed child's drain and cannot retroactively become a creation rejection. Initialization Stop still settles its final actions and never enables ordinary ingress. For atomic workers, InitializeWorker is a later exact-host request that reports the committed worker's initialization-effect outcome; it does not redo the pure fold or establish a second birth. Activation follows a successful ready report. This is a policy and derived composition law, not an additional actor-model guarantee. The remaining A01 proof obligation is an interpreter trace for each success, rejection, and stop path.

The interpreter port currently cannot realize this custody law directly: RoutedCreation exposes the child only by shared borrow or by consuming the complete request. A host that calls initialize(&mut child) before commit would have to dismantle and rebuild the rejected request, obscuring exact ownership. The pre-production regression in behavior-testkit/tests/creation_initialization_order.rs calls initialize(creation.child_mut()) through the staged request and fails with E0599 because that borrow is absent. The intended syntax leaves the same RoutedCreation owned by the host for InitializationRejected or HostRejected, and permits Established only after successful installation. The smallest public repair is one mutable-child borrow on the existing RoutedCreation runtime port. It reuses initialize, CreateChild, ChildCreationOutcome, and EstablishChild; it adds no transition type, effect lane, interpreter trait, or actor state. The aggregate-drift checkpoint is unchanged before and after: no aggregate control sum, subordinate alternative, branch, module, or public type name changes. The new method owns no arrival history, repeated cause, cardinality assumption, nested authority, semantic boolean, or positional syntax. The retained disposition is recorded below.

A01 retained result: RoutedCreation::child_mut is the single new runtime borrow port. It lets an EstablishChild host call the real pure initialization fold while retaining the complete request for typed rejection. The six-case testkit host trace checks reservation, fold, install/commit, effect settlement, and ingress authorization, including allocation failure, pure fold failure, host refusal with uninterpreted actions, initialization stop, and a post-commit effect failure that cannot undo birth. The focused tests and the 804-test workspace run passed. docs/actor-transition-algebra.md, docs/atomic-runtime-settlement.md, and docs/adapter-contract.md now state the same order; the atomic worker InitializeWorker request is explicitly later effect-settlement observation, not a second pure fold. Post-edit drift disposition is pass: no control-state sum, subordinate alternative, transition branch, source module, or public type name changed; one public borrow method was added and no historical state, false cardinality, nested authority, semantic boolean, or positional syntax was introduced. The testkit host witnesses that the typed port can realize this policy; the downstream Bombay Engine implementation still needs its own integration verification.

The isolated probes used Rust 1.95.0 and local path dependencies on the audited crates. No production mutation was made. Their relevant results are:

ProbeObservation
Unrenamed bombay-behavior dependency; ordinary #[behavior::behavior] countercargo check --offline fails with E0433: cannot find bombay_behavior; the identical source compiles after renaming the dependency to behavior
Renamed core plus unrenamed bombay-behavior-actors; ordinary #[pool_worker] assignment completionFails with E0433: cannot find bombay_behavior_actors; renaming the dependency and corresponding authored path to actors compiles
require_projection::<FifoRequests<NoSends, NoSends, NoSends, NoSends, NoSends, NoSends, NoSends, NoSends, NoSends>>(), with T: LogicalDeliveryProtocolsFails with E0277, establishing the missing product law even when every lane already has a projection
fn duplicate<W>(permit: actors::atomic::ActivationPermit<W>) { let _accepted = permit; }Still fails with E0277 after removing the second move; the existing negative example is not specific evidence of affine ownership
Mutation report with no baseline, one caught and one unviable mutantGate exits 0 and prints mutation coverage: 1 viable / 2 total
Mutation report with a successful baseline, one caught and one Failure mutantGate again exits 0 with the same coverage line
External caller invokes delegate_transition before initialization, then calls initialize twice on the same owned counterTest passes and observes all three state changes; the public composition ports rely on caller discipline

The mutation probes use two candidates with file a.rs and function name f, and baseline {"floors":{"a.rs::f":1},"known_zero_viable":[]}. Outcomes use the gate's existing summary and scenario schema; the tested command is behavior-mutants-gate check OUT OUT/baseline.json. These are acceptance bugs in the verdict tool, not results of a real mutation campaign.

A14 trusted-port evidence

The public InitializationTurn constructor remains private. The documentation now states the narrower truth: initialize(&mut B) and delegate_transition(&mut B, event) are trusted wrapper/runtime ports that can issue turns repeatedly or out of lifecycle order; the consuming Activate::initialize application path owns the once-per-definition rule. behavior/tests/trusted_ports.rs is a legal external caller witness: it delegates an event before initialization, then initializes the same definition twice, inspects all three complete empty Actions, and observes the three state changes. The focused test passed. This repair changes no actor effect, state type, or turn constructor visibility.

A09 testkit simplification

The testkit now imports the existing behavior_actors::Activate trait directly in its six callers; the forwarding InitializeTest trait and its public spelling are gone. The unused Criterion declaration and its 458 lockfile lines were removed without updating unrelated dependency versions. Fifteen tests with no .await now use the synchronous harness. Destination-only fixtures in the catalogue model files implement Protocol alone; they no longer pretend to own an inert Behavior lifecycle. The testkit bench check and all migrated test targets passed. This deletes one duplicate public trait, one dev dependency graph, and nine generated inert behavior implementations; it changes no actor transition or runtime effect law. The existing consuming Activate path and its tests are the caller-facing proof, so no replacement interface or no-op fixture was introduced.

The routing-invariant fixtures and work-queue unit tests also dropped their destination-only inert Behavior implementations. Their routes require only Protocol; the routing and queue tests still pass with those narrower fixtures. The pub-sub unit destination likewise now implements only Protocol.

A06 property-oracle evidence

The sequencer, deduplicator, and order-gate models now compare complete ordered delivery and reply vectors, including destination addresses, reply alternatives, rejected payloads, creation emptiness, and next verdict after each generated step. Their initialization actions are checked too. The deduplicator uses a non-Clone boxed payload and checks its original pointer through accepted delivery or duplicate rejection, so equal reconstructed values cannot masquerade as returned ownership. Configuration, readiness, health, cache, registry, and topic models now inspect successful actions, reply cardinality and destinations, and initialization rather than discarding those observations. Readiness generation carries the domain status enum instead of a semantic boolean; stale errors check the committed version. The independent map, deque, and list oracles remain separate from the production transition methods. Focused model and invariant suites passed. The work-queue model now checks initialization and every step's full assignment/outcome vectors, recipient, creation lane, and next verdict. It tracks distinct non-Clone owned work and unique reply destinations through both waiting and available FIFO queues; the focused property passed. The keyed pub-sub model now independently checks topic introduction order, recipient membership, complete successful actions, exact rejected commands, and the original allocation of an undelivered owned publication. Its full seven-test invariant suite passed. Four isolated temporary counterfactuals each caused the targeted property to fail: an extra reply, a wrong destination, a stop verdict, and a lost original boxed payload. The temporary test target and its regression artifact were removed afterward. No production actor state or effect type changed.

Source evidence at the audited revision:

  • A02/A08: macro resolution and consumer harness.

  • A03/A11: atomic product derivation and current projection tests.

  • A04: obsolete adapter fixture and activation permit fixture.

  • A05/A07: verdict implementation and gate definitions.

  • A06: catalogue models and catalogue invariants.

  • A09/A10: testkit API and driver.

  • A18: benchmark workload.

  • cargo nextest run --workspace: 783 passed, 0 skipped. Three nested Cargo fixture tests were reported slow; compilation and execution overlapped other audit builds, so these timings are not a performance baseline.

  • mdbook build docs: passed with this audit included in the book.

  • python3 -m unittest scripts/test_check_published_docs.py: three passed.

  • python3 scripts/check_published_docs.py target/doc: passed after building the updated guide. All local links in this audit also resolve in the source tree.

  • git diff --check: passed.

  • nix flake check: passed against the clean audited baseline, including its optimized nextest run (783 passed, 0 skipped), build, Clippy, documentation, doctests, formatting, dependency checks, and package-content check. The added documentation is checked separately by the book build and link checks above. The mutation campaign is a separate Nix package and was not run; its focused verdict probes are recorded above.

Change scope: one audit document and links from the engineering index and book contents. Production +0 / -0 / net 0; tests +0 / -0 / net 0; public API +0 types / -0 types. Every checklist item remains open; documenting a finding does not implement its repair. This paragraph records the audited baseline; the branch repair scope is measured above.

Repair verification on codex/repository-quality-repairs:

  • cargo nextest run --workspace: 790 passed, 0 skipped before the final gate-only test for viability collapse; that additional test passed in both debug and release, making 791 current workspace tests.
  • cargo test -p behavior-mutants-gate --bin behavior-mutants-gate and the matching --release invocation: 10 passed each.
  • cargo test -p bombay-behavior-macros --test crate_resolution: 4 passed.
  • Filtered actor adapter and activation-permit doctests and the core heterogeneous-birth doctest passed. An isolated rustc counterfactual confirmed E0277 for the missing host and successful compilation after adding its exact implementation.
  • The README example compiled in an offline external path-dependent consumer; python3 -m unittest scripts/test_check_published_docs.py passed four tests.
  • nix flake check: passed all 13 checks with the new fixture and audit document included in the Git source. The mutation campaign itself is a separate package and was not run.
  • mdbook build docs, python3 scripts/check_published_docs.py target/doc, and git diff --check HEAD: passed after the repair record was written.

Final verification of this repair batch before its branch commit:

  • cargo nextest run --workspace --no-fail-fast --test-threads 4: 810 passed, 0 skipped. The three external macro consumers were slow while sharing the fixture target; no test failed.
  • cargo test -p bombay-behavior-macros --test crate_resolution --offline: 4 passed with the nested lockfile aligned to the root vendored set.
  • nix flake check: passed all applicable aarch64-darwin checks, including optimized nextest, build, Clippy, docs, doctests, formatting, audit, deny, and package-content verification. The first run exposed the nested fixture lockfile mismatch; the corrected run passed.
  • bash scripts/check_published_packages.sh: passed. It assembled the three archives and compiled an extracted-package consumer using the README declarations and both public macro entry points.
  • cargo bench --profile dev preflights for protocol_matrix and fifo_pool passed with three short samples each. These are workload checks, not performance claims. mdbook build docs, README link tests, cargo fmt --all -- --check, and git diff --check HEAD passed.

At that checkpoint, thirteen checklist items were complete and seven remained open. The source changes under crates/*/src were +609/-430 physical lines (net +179), including the stricter mutation verdict and logical-host projection. The branch deletes the duplicate BufferSends and test-only InitializeTest public names and adds one associated logical-protocol type and one child-borrow method to existing ports. No actor control-state variant was added. This scope measurement is diagnostic; it does not certify the seven open design and integration items.

The later branch currently has fourteen complete items and six open items. After nix flake update, nix flake check passed all ten applicable aarch64-darwin checks on signed commit d332af9, including build, Nextest, Clippy, docs, doctests, both formatting checks, audit, deny, and package verification. These gates do not close the six remaining design, mutation, and downstream integration criteria.

Against merge base 435560ce7bea8ad3330ee2d42e5034f837a80602, the current branch's source changes are net −78 lines in behavior/src, −1,089 in actors/src, −4 in behavior-macros/src, and −8 in behavior-testkit/src: 1,179 fewer production and testkit source lines. The crates/ tree as a whole is net +332 lines because focused tests and the stricter mutation gate grew, alongside benchmark and supporting changes. These git diff --numstat counts are diagnostics; the six open checklist items still decide whether the remaining interfaces and aggregate states are essential.

References

Repository acceptance criteria are in AGENTS.md. Current semantic references are actor transition algebra, behavior layer laws, atomic runtime settlement, and the normalized proxy, fixed supervisor, dynamic supervisor, FIFO pool, and keyed pool laws. Their ordering conflict is tracked by A01; this audit does not silently choose a new semantic law.

Rust interface guidance comes from the Rust API Guidelines. The rustdoc book describes compile-fail tests; the Cargo check documentation describes target selection. Rust guidance is distinct from Bombay's stricter local policies on naming, semantic booleans, imports, and static dispatch.

Public surface inventory

This inventory supports A13. #[doc(hidden)] changes Rustdoc display, not Rust visibility. The counts below are annotation sites in source, so a grouped re-export and its original declaration each count once. The current branch has 10 sites in crates/behavior/src and 22 in crates/actors/src; the earlier audit counted 25 and 89 before the documentation visibility review.

Hidden core declarations

OwnerAnnotated declarationsContract ownerVisibility decision to review
actor/creation.rs, occurrence proofStructuralChildOccurrence, ChildCreationProduct, ChildOccurrenceResolution, ResolveChildOccurrenceDescriptor, BirthNodeAt, ChildOccurrenceProductAtGenerated code obligationThe macro and structural child products implement these proofs. A visibility change needs compile-pass and forged-occurrence compile-fail witnesses.
actor/creation.rs, protocol projectionBirthModeProtocols, BirthNodeProtocols, BirthNodeLogicalHostsGenerated code obligationThese traits project closed birth and logical-host products; consumers can name the resulting associated types without constructing the proof nodes.
actor/creation.rs, creation stagingChildProduct::stageSealed structural conversionChildren::into_creates calls this method to turn the closed heterogeneous product into an ordered Creations batch. Only NoChildren and ChildCons implement the sealed trait. The interpreter receives the resulting batch through the creation effect; it does not call stage.

ChildOccurrence::Resolution and DeclaredChildOccurrence are now visible because manually authored roles must name them. BirthProtocolProduct is visible because generic logical-host owners constrain and append that public product. Rustdoc lists both names and the caller suites exercise them. The private Recipient::new no longer carries an ineffective documentation marker. CreationSettlement, CreationSettlements, and CreationsSettled are now visible because external callers name them when retaining or returning exact child-creation custody. InterpretCreations is also visible: the real Bombay runtime names it in the bound for its action interpreter. This is a source witness for required port visibility, not yet an A17 integration verdict. CreateChild::into_parts is visible because external creation-interpreter tests and the inspected Bombay child host consume it to retain exact owned creation parts across acceptance or rejection. The method did not gain a new capability; its Rustdoc now describes the existing custody transfer. CreationCorrelation<P, Occurrence> is visible because external ActionItem implementations name it as an exact, non-authoritative creation prerequisite. Its occurrence parameter and private fields keep equal numeric IDs at different child positions distinct. CreationId::get is also visible because the actor catalogue derives shutdown and operation correlations from it, and external interpreter tests inspect those exact values. Its Rustdoc now states that the numeric projection is neither actor identity nor proof of a committed fresh child.

Hidden actor declarations

OwnerAnnotated declarationsContract ownerVisibility decision to review
atomic/{dynamic_supervisor,fifo_pool,fixed_supervisor,keyed_pool}/{event,requests}.rsDynamicSupervisorEvent, DynamicSupervisorRequests, FifoEvent, FifoRequests, FixedSupervisorEvent, FixedSupervisorRequests, KeyedEvent, KeyedRequestsRuntime portPublic associated event and send products let an interpreter carry complete typed lanes; the aggregate owns their transition semantics.
atomic/fixed_supervisor/lifecycle.rsFixedLifecycleRouteGenerated code obligationThis sealed route proof is implemented for the finite fixed-supervision lifecycle forms.
atomic/pool/mod.rsCompletesAssignmentsGenerated code obligationThe sealed completion capability belongs to generated pool workers and declared completion products.
atomic/stable_proxy/{effects,protocol}.rs and atomic/mod.rsProxyEffects and its re-export; ProxyEvent as a concrete associated event typeStructural event/effect productsThe host and typed proxy effects must keep rejection custody and every ordered lane; application callers use the typed Behavior projections and event ingress. ProxyDrain, WorkerStartResult, and ProxyOperation::creation are now visible because callers match the concrete outcomes or inspect the exact creation correlation.
atomic/worker/mod.rsHostedInitializationInternal type aliasWorkerRecovery::into_retirement returns the actual Actions type through this alias. The exact worker and actions are now visible on WorkerRecovery; WorkerAttempt is a visible opaque correlation value. Whether the alias itself needs an external spelling requires a real host caller.
lifecycle/shutdown_coordinator.rsHeterogeneousShutdownItem, ChoiceSettlements, HeterogeneousShutdownChoiceSettlementGenerated code obligationThe closed heterogeneous choice product supplies the typed settlement shape.
atomic/mod.rs, atomic/pool/mod.rs, and lifecycle/shutdown_coordinator.rsGrouped re-exports of the declarations aboveSame as original declarationThe re-export annotations add no second capability; each name remains publicly reachable through its parent module. CustomerDelivery is now visible because external interpreters must name it; FixedBuilder, FifoError, and KeyedError are visible because applications name the inferred builder and aggregate errors.

This table classifies ownership but does not by itself justify retaining each public spelling. In particular, an associated type that mentions one of these values is not proof that applications must name it. Closing A13 still requires caller-facing compile witnesses, a trait-implementor inventory, and a repeatable compile-cost comparison before changing visibility or bounds. The branch-level cold comparison below measures aggregate compiler impact; it does not replace a focused before/after comparison for a future individual bound.

AssignWorker::target and CustomerDelivery are now visible runtime ports. The interpreter obtains a clone of the exact recipient capability through target, then consumes settle to transfer the delivery while the request retains its receipt. A rejected keyed outcome retains the original customer route in the complete CustomerDelivery action. The former public receipt and into_parts assembly methods remain atomic-module-only.

ProxyDrain and WorkerStartResult are visible domain outcome sums because external supervisor and proxy callers match their concrete alternatives. ProxyOperation::creation is visible for trusted interpreters selecting the exact proxy; its numeric value remains creator-local correlation, not actor identity or installation evidence. ProxyEffects and ProxyEvent remain hidden structural products reachable through typed behavior projections and event ingress; their documentation status grants no extra authority.

WorkerRecovery and WorkerAttempt are visible opaque custody and correlation values. WorkerRecovery::into_retirement consumes the failed worker and untouched initialization actions together. WorkerAttempt::creation reveals only the creator-local correlation; both constructors and their fields remain private. The HostedInitialization alias still has no public crate-root spelling, so its external naming need remains open for the real host witness.

ObserveCreation<P, Occurrence> is now visible as the typed same-action creation-observation request. Its prerequisite remains exact CreationCorrelation<P, Occurrence>, and its creator-local numeric ID does not establish a child or substitute for the protocol and occurrence types.

The complete worker initialization and activation port is visible: the existing InitializeWorker, WorkerInitializationOutcome, WorkerInitializationReport, InitializationAttempt, ActivationPermit, BeginActivation, WorkerActivation, ActivationStartRejection, and WorkerInitializationFailure types and their already-public methods now have Rustdoc pages. The permit remains non-forgeable, and the host must admit Started before polling the activation plan. Exposing these pages adds no constructor, field, interpreter effect, or transition.

The P2 assignment custody witness narrowed two formerly public methods after external caller tests proved the consuming settle operation. Compile-fail fixtures reject receipt extraction and splitting the request with E0624, while a second settlement fails with E0382. The corresponding real FIFO and keyed caller suites, benchmark, and fuzz campaigns use actual exact-delivery admission. This closes those two spellings only; proxy assembly remains open.

The P2 proxy owner settlement also made the previously doc-hidden ProxyOperationId export unnecessary. External interpreters now receive the complete control through ProxyControlAdmission and return the exact actor or control; only the owner retains the ID. A dedicated external fixture rejects the ID name with E0603, while the receipt-constructor fixture independently rejects new with E0599. The ID remains available to private supervisor state and receipt settlement through a crate-private re-export.

The exact assignment and proxy interpreter products are now visible in the atomic Rustdoc index: AssignWorker, AssignmentReceipt, ProxyControl, ProxyOperation, ProxyInputReceipt, and ProxyInputResult. These were already public Rust names required by external InterpretItem and ProxyControlAdmission implementations. Their fields and owner-only receipt constructors remain private; hiding the item pages served no capability boundary. Six actor annotation sites were removed, leaving 75.

The worker-preparation interpreter path is also visible: PrepareWorkers, PendingWorkerPreparation, WorkerPreparation, and both request phases' source_and_role, accept, and reject methods. External fixed/FIFO tests and Bombay's inspected source already name this progression. The ticket, constructors, fields, and owner settlement remain private. Nine more actor annotation sites were removed, leaving 66.

DiagnosticRoute, DiagnosticAction, DiagnosticAccepted, and their four existing constructors are now visible in Rustdoc. External actor and interpreter-contract suites already name these products to settle routed and route-free diagnostics, while the sealed route trait still limits its implementors. Removing eight documentation annotations changes no Rust visibility, constructor, or transition; 58 actor annotations remained at that checkpoint, with 56 after exposing the customer-delivery ports. The proxy outcome and correlation documentation repair leaves 54 sites. The returned-worker custody repair leaves 50 actor sites. The worker initialization and activation port repair leaves 23 actor sites. The creation-observation port repair leaves 22 actor sites.

WorkQueue now keeps worker-route cloning and equality on construction and transition operations, where queue inspection and duplicate availability use them. Its protocol identity accepts a lawful ReplyRoute without PartialEq. The external protocol-only caller failed on the previous aggregate bound with only E0277 and passes after the bound move; the FIFO transition suite still exercises the comparable route used by a running queue.

Twelve unwrapped catalogue actors now expose BehaviorBase<Base = Self> for opaque domain types without inheriting bounds used only by construction or transition: Acknowledgements, Resolver, Configuration, Readiness, Machine, Topic, PubSub, Presence, Lease, Barrier, Workflow, and OrderGate. The external caller test failed on their former Clone, Eq, Copy, PartialEq, or Ord bounds and passes after removing only those impl-level bounds. Their stored state, protocol, and transition contracts are unchanged. Router remains structurally bound by its route and strategy policy and needs a separate owner review.

Deduplicator and OrderGate now also expose protocol identity for an opaque key. Deduplicator exposes its read-only base projection on the same terms. The key comparison bounds remain on the operations that actually deduplicate or order messages. A focused caller failed before the change only on these three impl-level bounds and passed afterward; the routing transition suite remained green.

PriorityQueue now also accepts an opaque priority type at protocol identity and base projection. Its Ord proof remains required where construction and transition use the heap. The external caller failed on the old aggregate bound and passes after this move; the stable-priority selection trace remains green.

A source scan after these batches found Router as the only catalogue Protocol or BehaviorBase impl whose header still carries a copying, comparison, or ordering bound. Its route equality is used for membership and its current RoutingStrategy<Route> contract requires Clone + PartialEq. The aggregate review retained those bounds: construction deduplicates by route identity, Add/Remove compare exact members, and a route attempt clones its policy candidate for rollback on rejection. A type-level router with an uncomparable route would have no lawful construction or transition, so removing only a repeated header bound would add no usable protocol contract.

Public trait implementors

The source declares 77 top-level public traits: 55 in behavior and 22 in behavior-actors (counted with rg '^pub trait '). The following inventory accounts for every declaration. “Author” means an application defining its own typed actor, effect, or child protocol; “interpreter” means the code that settles an exact typed request. A structural proof may be public because a generated or manually authored product must implement it, even if ordinary applications should not mention it directly.

OwnerTraitsLawful implementors and reason for the port
transition.rsProtocol, BehaviorAuthors declare a stable typed destination and its pure transition; wrappers implement the same contract for composed actors.
transition.rsLogicalHostRequirements, BehaviorBaseBlanket logical-host projection for any qualifying behavior; authored behaviors and wrappers expose the underlying base.
transition.rsBehaviorLayerA concrete construction closure or an authored construction type; the existing blanket closure implementation is the common case.
user_event.rsUserEvent, ComposedEvent, EventIngress, ChildInputIngress, InjectEvent, RecoverEventAuthored event sums and structural wrapper event products; these preserve a typed user-message lane and lossless event injection/recovery.
actor/addressing.rsAddress, EndpointAddressAddress-space authors and concrete address types; the latter provides the endpoint form used at the interpreter edge.
actor/addressing.rsInterpretEstablishedInterpreters of an exact established recipient capability.
actor/creation.rsChildRole, ChildOccurrence, ResolveChildOccurrence, EstablishChild, ChildCreationProduct, DispatchBirthAuthors or generated role declarations establish exact child positions; structural birth products and interpreter adapters resolve and dispatch them.
actor/creation.rsChildPosition, BirthNodeAppend, ChildOccurrenceResolution, ResolveChildOccurrenceDescriptor, BirthNodeAt, ChildOccurrenceShape, ChildOccurrenceProduct, ChildOccurrenceProductAt, ChildProductClosed structural child-position and birth-product proofs; source and generated products implement these to retain exact occurrence and custody.
actor/creation.rsBirthMode, BirthProtocolAt, BirthProtocolProduct, BirthProtocols, BirthModeProtocols, BirthNodeProtocols, BirthNodeLogicalHostsAuthored birth modes and structural projections enumerate child protocols and logical hosts without runtime lookup.
effects/actions.rsActionSettlements, BehaviorSettlements, CreationSettlements, AppendSendComplete structural action/creation settlements and typed send-product append operations.
effects/actions.rsInterpretCreationsInterpreter-bound traversal of one exact ordered creation product.
effects/sending.rsClassifySettlement, ActionItem, SendSettlements, SendInput, SendEffects, LogicalDeliveryProtocols, SendsFor, SourceAction, SourceSettlementCustody, ReturnToEmitterFor, InterpreterRequestAuthors and concrete structural products define the request, settlement, routing, and logical-destination equations. The #[behavior] macro derives the logical-host projection for named sends in field order; other authored custom sends products state it explicitly. A generated product is private by default and may be exported with sends = pub { ... } when its field types are public.
effects/sending.rsInterpretItem, InterpretSends, SourceAdmissionInterpreters settle exact items; concrete send products traverse them; actor ingress admits an exact returned source action.
activation.rsActivateBlanket implementation for a behavior that can enter its consuming initialization path.
atomic/diagnostic.rs, atomic/fixed_supervisor/lifecycle.rs, atomic/pool/mod.rsDiagnosticRoute, FixedLifecycleRoute, CompletesAssignmentsSealed diagnostic, fixed-lifecycle, and completion products; only the declared finite alternatives implement them.
atomic/worker/mod.rs, atomic/worker/preparation.rsActivationPlan, WorkerSourceAn author supplies a concrete worker activation plan and a source that returns complete prepared or rejected worker custody.
atomic/stable_proxy/operation.rsProxyControlAdmissionA trusted interpreter of a statically selected proxy child implements this port. It receives a concrete ProxyControl and returns the exact admitted actor or the owned control with a reason; the operation ID stays with ProxyOperation. The actor suites provide local interpreters, and the isolated Bombay runtime has an implementation, but its unmerged source does not prove production integration.
composition/delivery_route.rsDeliveryRouteSealed transferable logical, established, and mixed routes. An owner constrains its associated protocol address to BehaviorAddr<Owner> when needed; no second route trait is required.
lifecycle/child_shutdown.rsBeginShutdownPhases, DeclareShutdownPhase, FinishShutdownPhases, AssignAt, AllAssignedStructural shutdown-plan composition and the finite proof that every required child was assigned.
lifecycle/shutdown_coordinator.rsShutdownTargetAtA typed child-position shutdown target in a heterogeneous plan.
lifecycle/termination_monitor.rs, lifecycle/termination_propagation.rsTerminationObservationTarget, TerminationTargetExact recipient forms for observing and propagating termination.
protocol/established.rsInterpretEstablishedObservation, InterpretEstablishedShutdownInterpreters of exact established observation and shutdown requests.
routing/router.rsRoutingStrategy, RouteKeyAuthors select a concrete policy and define the application message key; the catalogue supplies round-robin, least-loaded, consistent-hash, and rendezvous strategies.
stash.rsStaticallyInfallible, StashStatusThe former is sealed to infallible forms; the latter projects stashed-message status through multiple existing wrappers.

The table identifies implementor roles, not proof that every spelling should stay public. In particular, the structural rows still need external compile witnesses before visibility can be reduced. StashStatus already has multiple real wrapper implementations, so treating it as a redundant one-implementation trait would be incorrect. Any further bound change needs a new caller diagnostic and focused compile-cost comparison for that particular edit.

Canonical export ownership

The crate roots are the canonical export lists. This table classifies their complete groups by the owner that justifies the public names; mixed groups are further split by the hidden-item and trait tables above. No public spelling is retained merely because a private associated type mentions it.

Crate-root export groupPublic contract owner
Core actor::addressingApplication address, logical/exact recipient and delivery capabilities; exact-delivery admission belongs to the interpreter.
Core actor::creationAuthored child roles and staged creation are application algebra; occurrence/birth products are generated structural proofs; establishment, creation settlement, and exact returned custody are interpreter ports.
Core effects::{actions,sending} and nextActions, typed send products, and next decisions are application algebra; Interpret*, settlement, and source-admission contracts are interpreter ports; product traversal and append proofs are structural.
Core transition and user_eventProtocol, Behavior, BehaviorLayer, turns, and event ingress are application and wrapper contracts; event-path and logical-host projections are structural composition proofs.
Actors activation and atomicActive and aggregate constructors/outcomes are application contracts; exact assignment, proxy, worker, observation, diagnostic, and preparation custody is the interpreter surface; event/request products and sealed completion/lifecycle traits are structural. The hidden-item table identifies every intentionally hidden member.
Actors composition, machine, shutdown, stash, termination, and watchConcrete application wrappers and protocol products; DeliveryRoute is the single sealed transferable route equation.
Actors lifecycle and protocolAuthored shutdown/observation capabilities and results are application contracts; exact lifecycle, timer, observation, and shutdown admission are interpreter ports; closed child-position products are structural.
Actors discovery, operations, persistence, routing, time, and workflowApplication templates, commands, outcomes, configuration values, and typed policies. Their concrete effects use the core interpreter ports.
Macros SendProduct, behavior, and pool_workerGenerated-code obligations producing the same concrete products and bounds available to handwritten callers.
Testkit TestRecipient, Mailbox, DriveDisposition, Trace, drive, and modelTest-only caller and independent-model API; none is a production interpreter.
Mutation gate binaryNo public library API; the command and CI verdict contract are the exported developer interface.

All 77 top-level public traits have implementor roles in the preceding table. The 10 remaining hidden core sites are sealed or generated birth/occurrence proofs. The 22 remaining hidden actor sites are structural event/effect products, sealed generated proof traits and their grouped re-exports, plus the internal HostedInitialization type alias. The CustomerDelivery re-export from atomic::pool remains hidden because the canonical atomic::CustomerDelivery page is visible. External interpreters can name the actual request, outcome, receipt, and rejection values without naming those hidden structural products. A further visibility reduction would need its own caller witness; it is not part of this release review.

Cold actor-library compile comparison

On aarch64-darwin, the Nix shell at 1aeaed1 supplied Cargo 1.95.0 for both revisions. Each run used a newly absent CARGO_TARGET_DIR, the same command shape (cargo check --manifest-path REV/Cargo.toml -p bombay-behavior-actors --lib --locked --offline -q), and ran sequentially. The actor crate's Cargo fingerprint recorded the same feature list, profile, compiler configuration, and dependency identities in both revisions.

RevisionCold run 1Cold run 2Actor .rmeta
main at 435560c184.54 s180.09 s27 MiB
Audit branch at 1aeaed14.46 s3.97 s5.8 MiB

The measured command checks the actor library only, not tests, downstream applications, or release builds. The revisions differ in many source files, including macro and actor implementations; the observation cannot attribute the difference to any one A13 bound or predict downstream compile time. It does show that this branch's actor-library metadata and cold check cost did not grow under this controlled comparison.

Exact observation surface migration

Two owners represent distinct laws: ObservationAuthority<P> owns one exact protocol-matched cancellation attempt, and ObservationRelationship<P> owns cloneable nonauthorizing accepted identity. ObserveEstablished::new(id, recipient) owns fresh private correlation without another public issuer, key, or error type; construction occurs outside Behavior folds. CancelObservation::new consumes authority and loses its former Copy/Clone API. The established report sum returns whole rejected requests, so it requires the owning RecipientAddress capability contract. Its Started, Stopped and Cancelled variants no longer carry a separately forgeable numeric identity. The sealed target request port is mutable one-shot emission, the public monitor constructor consumes a prepared Observe, and consuming monitor/target/shutdown access recovers whole owned values. These existing-signature and variant changes are breaking even though there are only three new public nominal types.

PRD: Complete interpreter ownership and startup contracts

Date: 2026-09-29. Status: Behavior-owned contracts implemented on the repository-quality release branch; cross-repository P5 acceptance pending. The implementation ledger separates local proof from the future Bombay/Address runtime witnesses. This revision supersedes the 2026-09-28 creation-and-delivery proposal in this file.

1. Objective and implementation baseline

Make the current Behavior and Behavior Actors code fully interpretable by Bombay through small, concrete capability interpreters. Complete rejected request return, retained acceptance, and startup custody before attempting a broader redundancy refactor. Preserve the existing pure policies and aggregate transition authorities.

The implementation baseline is current Behavior commit 6ef850f47852b4a90a6eae7633757a9e5a1c9d6b, not the older registry release. The review began at de8f1bf264366da29992c0061d5bae9888353bd5 with 37 modified files; those pending implementation/test changes were committed during review as b46923c; 6ef850f then updated the audit's follow-on work description. They are part of this baseline, not changes to revert or recreate. At implementation start, record the then-current merged commit or complete tree snapshot and recheck the seven contract files fingerprinted in section 13.

The adjacent Bombay working tree was also inspected, based on HEAD a7a66e3912731923015560463cd2c9e5e76fc041 with substantial pending changes. Observations below about Driver, launch, and local hosting refer to that current source. Its lock still selects Behavior/Actors 0.17.0 and Address 0.2.0. That is an integration constraint to update, not the upstream design baseline. Do not make current source conform to an obsolete locked signature.

The deliverable of this review is this PRD. It does not claim that its proposed methods compile, that startup has already been repaired, or that all catalogue machinery is redundant. A prescribed API below must first pass its specified external regression; compiler fallout cannot invent additional architecture.

Success criteria

  • A runtime can attempt real delivery of AssignWorker and ProxyOperation and return the complete original request on rejection, without cloning during settlement or assembling private correlations. FIFO's existing retry policy deliberately copies a Clone job before delivery and retains the original.
  • Explicitly retained acceptance survives continuing turns through the existing generic custody path. Ordinary discharged acceptance does not accumulate.
  • Fresh commitment, initialization completion, endpoint publication, and worker activation have distinct, implementable meanings. Initialization runs once.
  • Every supported failure has an exact outcome and a surviving owner for every value the protocol still owns. Consumed actions are never reconstructed.
  • A downstream fixture using public APIs, real Communication, and real Driver proves the contracts. Manually manufactured successful host results do not count as that evidence.
  • Runtime code contains no duplicate pool, proxy, or supervisor transition law.

Scope boundary

Behavior / Actors ownsBombay and primitive runtimes own
Pure policies and aggregate stateDelivery and admission attempts
Typed requests and source correlationsTasks, clocks, endpoint publication
Consuming settlement and complete rejection returnConcrete initialization execution and startup evidence
Accepted-value retention declaration and static compositionRetained runtime values and parent-to-root retirement
Readiness, recovery, assignment, and supervision decisionsObservation of actual execution and termination

Do not add a supervisor abstraction, runtime registry, erased envelope, second Driver, callback-driven behavior, or lifecycle engine. Do not change FIFO/keyed selection, fixed/dynamic supervision policy, or actor cardinality to make their implementations look alike. Distributed execution, Entity redesign, Mnesis, Selo, and transport replacement are outside this project.

2. Current-code findings

Verified contract defects

IDCurrent owner and evidenceConsequence
D1actors/src/atomic/pool/assignment.rs: AssignWorker::into_parts exposes target, assignment, receipt; returned is restricted to crate::atomic. receipt() can separately reproduce receipt evidence.Actual transport rejection returns the assignment but an external interpreter cannot reconstruct the complete request lawfully. Public decomposition also separates evidence that ought to stay together during settlement.
D2actors/src/atomic/stable_proxy/operation.rs: private request fields, public into_parts, and public ProxyInputReceipt::new.A runtime can issue acceptance, but cannot return a rejected control after consuming the operation. Independently supplied creation, endpoint, and operation evidence can be assembled in the accepted constructor.
D3behavior/src/effects/sending.rs: SourceSettlementCustody for Vec<ActionItemResult<Item>> unconditionally returns Exhausted(self). DiagnosticAccepted::Terminal owns its diagnostic.Continuing Driver execution drops terminal evidence. The same blanket path also warrants correction for rejected, blocked, corrupt, and untouched requests; they are residual ownership, not discharged receipts.
D4behavior/src/actor/creation.rs: HostRejected requires current child plus untouched initialization Actions.It cannot represent a failure after consuming those actions. Adding a reason or exposing a constructor cannot solve this ownership mismatch.
D5Current Bombay establish_child waits for spawn_owned_with publication; its panic/cancel/early-end branch panics. SpawnError::from_local treats settlement failure as unreachable.The runtime cannot currently realize the documented established-child/initialization-result distinction for all startup outcomes.
D6Current Bombay LocalEnvironment::activate calls Address try_claim before commit(actions). Address makes a claimed endpoint resolvable immediately.Publication callback delay does not hide the endpoint. Moving the fallible claim after effects would create the D4 failure instead.
D7Current Driver calls environment.publish() in rejected-initialization, corrupt-initialization, and accepted-initialization-stop branches.Hidden Address reservation alone cannot satisfy the selected no-publication law; these generic startup branches must retire without publishing.

Paths in this table are relative to crates/ in the named repository.

Existing machinery to retain

  • ItemSettlement, SettledItem, Interpretation, and ActionSettlement already own total ordered interpretation, rejection, corruption, and suffixes.
  • SourceActions/SourceSettlements already return exact results to a live emitter. SourceCustody::{Exhausted, Retained, Admitted, Closed} already distinguishes terminal retention from live ingress.
  • Driver already keeps Retained settlements across continuing turns and sends them to retirement. Fix D3 upstream; do not special-case diagnostics in Driver or retain every successful receipt there.
  • InitializeWorker::resolve already reunites a host result with the original plan and issues the correlated activation permit. It is not permission to initialize a definition a second time.
  • WorkerInitializationFailure already distinguishes rejected effects from interpreter corruption. Child action settlements belong in runtime custody, not in a new supervisor error sum.
  • ShutdownEstablished::settle demonstrates an owner consuming a request at an interpreter seam. CustomerDelivery demonstrates complete rejected-route custody. Neither proves a universal delivery wrapper is necessary.

Documentation conflicts to fix with implementation

atomic-runtime-settlement.md and actor-transition-algebra.md commit a fresh host before interpreting initialization effects. adapter-contract.md also contains an effects-before-endpoint sequence and a general short-circuit failure statement. Reconcile these with section 6, including the difference between ordinary rejection and corruption. Do not treat stale historical engineering proposals as another normative contract.

The generic testkit Driver explicitly accumulates actions without interpreting them. proxy_operation_settlement.rs presently proves type compatibility using an absent value, not rejected transport custody. Existing creation-order tests use a model host. These are useful tests with narrower claims than downstream execution; retain that distinction in reports.

3. Laws and authority

LawClassificationRequired implementation consequence
Newly allocated actor identity is fresh; creation and behavior replacement are different operations.Actor researchNo collision overwrite, reused endpoint substitution, or inferred replacement provenance.
A pure transition returns explicit communication, creation, and next-behavior effects.Bombay's typed realization of actor operationsExecution remains outside Behavior; no Tokio or hidden delivery in transitions.
Rejection returns every still-owned input; acceptance transfers the payload exactly once.Derived affine protocolThe request owner retains correlation during interpretation and reconstructs only from the actual returned payload.
Success status and remaining custody are independent.Derived composition lawAn accepted terminal value can have Accepted status and Retained custody simultaneously.
Commit fresh creation before dependent same-action operations; interpret initialization before ordinary transitions.Bombay policyDependent operations see the committed child, and initialization is never replayed.
Public logical resolution remains absent until successful continuing initialization.Bombay publication policy selected by this PRDUse exclusive hidden reservation; private host commitment is distinct from publication.
Rejection continues independent effects; corruption preserves prefix, faulting value, and untouched suffix.Existing Bombay interpretation lawNo ? that loses siblings; no rollback fiction.
Each aggregate chooses its own complete next state and actions.Library design constraintRequest settlement performs transfer/reunion only, never recovery, retry, or supervisor transitions.

Primary research checked for this revision: Agha, Mason, Smith, and Talcott, A Foundation for Actor Computation, §3, especially pp. 19–20, distinguishes fresh newadr, initialization, and receptionists. It does not prescribe Bombay's startup transaction, rejection sums, readiness, or publication API. Primary paper.

Owner-controlled reconstruction follows the information-hiding criterion: request representation belongs to its owner, execution to its interpreter. This is a design inference, not an actor theorem. Parnas. The aggregate remains responsible for its invariant; subordinate protocol values do not become transition authorities. Evans, Aggregates. Use concrete types to express the resulting capabilities and ownership. Rust API guidance.

4. Delivery settlement contract

4.1 Compare complete ownership equations first

DimensionAssignWorker<P, Job>ProxyOperation<Source, Worker, Plan>
PayloadAssignment<Job>, including completion authorityProxyControl<Worker, Plan>; start/replacement carries definition and plan, shutdown does not
DestinationAlready-established exact worker recipientCreator-local proxy creation resolved to an exact private control endpoint
Evidence held by ownerAssignment receipt/correlationCreation ID, affine operation ID, and static source identity
Accepted receiptOriginal assignment receiptOriginal creation/operation evidence plus exact resolved EstablishedActor<StableProxy<...>>
Expected rejectionExactDeliveryReasonChildInputReason, including missing binding or closed control
Subsequent resultWorker completion, possibly racing exit/admissionProxy outcome, possibly racing exit/admission
Live settlement destinationSource = SelfDeclared Source

They share the owner retains evidence while a lower capability consumes or returns the payload law. They do not share the same destination resolution, receipt, rejection, or later outcome. Keep both concrete request types. Reuse ItemSettlement and existing delivery capability; do not introduce a shared public envelope or a universal reconstruction trait.

FIFO's accepted-worker retry policy retains its original Job while the worker receives a clone. A rejected assignment returns that retained original to the pool; the settlement method must not create another copy. A job type without Clone cannot satisfy this policy after accepted delivery and worker loss. Support for move-only FIFO jobs would require an explicit at-most-once policy or a worker protocol that returns the job, with different failure semantics. That policy is outside this PRD.

4.2 Required external syntax and transfer

The intended interpreter call for each request is a consuming request.settle(&mut delivery_capability).await. This operation exists only at effect interpretation. It returns that request's existing ItemSettlement<Self, Self::Accepted, Self::Rejection, Self::Prerequisite>. It does not return SettledItem; product traversal owns attempted/untouched provenance. No application constructor or wrapper-depth argument is added.

Assignment implementation: inside the owning module, separate the receipt from EstablishedDelivery<P>, invoke the existing InterpretItem<EstablishedDelivery<P>, RootEvent, Path> capability, and reunite its returned delivery with the receipt. Root/event path generics belong only on this interpreter method if needed; they must not enter pool construction.

Proxy implementation: the lower operation takes the original CreationId and ProxyControl, resolves the exact private proxy, and returns either its exact established actor after control admission, or the same control and its reason/fault. It must never receive the private operation ID. The owner adds that held ID and the held creation correlation to acceptance or rejection.

The existing ChildInput accepted unit does not provide the exact actor needed by ProxyInputReceipt. Select one narrow static interpreter seam, ProxyControlAdmission<Worker, Plan>, with one admission method taking those creation/control values. Its return is the existing ItemSettlement shape with ProxyControl as returned item, exact proxy actor as accepted value, ChildInputReason as rejection, and Never as prerequisite. No new result wrapper is needed. The seam is an intentional third-party interpreter port; its generic parameters select concrete worker/plan protocols, not policy.

The port's implementation must use the containing ProxyOperation interpreter's statically selected child occurrence. Equal numeric IDs in different creator namespaces or occurrences must remain distinct. Do not add runtime type lookup or guess the child role from the ID.

This specifies an API candidate with one new interpreter trait, not a proven signature. Before production, compile the external syntax with two concrete worker/plan substitutions and a real proxy control rejection. If existing static child admission can return the same exact evidence without a new seam, use it and delete this proposed trait from the ledger. Do not ship both ports. No implementation agent may widen the seam to implement lifecycle policy.

4.3 Complete settlement table

Lower-capability outcomeAssignment ownerProxy owner
AcceptedConsume payload once; return the held receiptConsume control once; join exact admitted actor with held creation/operation evidence
RejectedReturn exact target, actual returned assignment, and held receipt as SelfReturn original creation, actual returned control, held operation, unchanged source as Self
Corrupt before transferReturn complete request and exact faultReturn complete request and exact fault
No committed proxy bindingNot applicable to an exact recipientReturn complete request with existing missing-binding reason
Untouched after earlier product corruptionProduct retains original request unchangedProduct retains original request unchanged

Both current prerequisites are Never; do not add a synthetic blocked state. Acceptance proves admission, not execution, completion, readiness, or restart. A close between resolution and admission is a real rejection, not corruption and not a preflight-liveness success.

The lower interpreter is trusted to return the actual payload and destination it received. Rust cannot distinguish all same-typed runtime values or prove a foreign interpreter honest. The owner API must make receipt substitution unavailable to ordinary callers, keep evidence out of the lower port, and test runtime identity preservation under two simultaneous requests. Do not claim a compile-fail test proves same-type runtime identity.

4.4 Close the old assembly surface

After the external proof succeeds, remove or narrow external AssignWorker::receipt, AssignWorker::into_parts, ProxyOperation::into_parts, and ProxyInputReceipt::new wherever they permit independent construction of evidence. Keep only necessary read-only inspection and owner-internal terminal decomposition. AssignWorker::returned remains owner-private or is inlined into its sole owner path; it must not become the public fix. Inventory all legitimate downstream consumers before narrowing.

Negative fixtures must reject external receipt assembly, double settlement, wrong protocol/source/occurrence, and using an operation after moving it. Tests inside the owning module do not establish these privacy guarantees. Cancellation must not drop the only settlement future while it owns the request. Bombay keeps the transfer alive to a settled result or retains its actual owned in-flight work through retirement; neither method creates a task.

5. Generic retained acceptance

5.1 Selected representation

Keep acceptance status separate from custody. Add an owner-controlled consuming operation to the existing ActionItem contract, with the intended signature:

fn retain_accepted(accepted: Self::Accepted) -> Option<Self::Accepted>;

Some(value) is exactly one accepted value still requiring terminal custody; None means that receipt has been discharged. This is a residual value, not a boolean semantic flag or a second settlement vocabulary. Provide the ordinary discharged default on this existing method so existing unit-receipt items do not acquire a mandatory no-op policy, extra bound, or marker. The method's documentation must say that its default permits destruction of the receipt.

DiagnosticAction overrides it: Delivered discharges; Terminal(value) returns that exact accepted value. Review every current type Accepted owner before retaining the default. Receipts carrying remaining authority must opt in where they actually use the source-free custody path. Do not apply this operation to SourceSettlements: their receipt must first return to the source.

The proof needs both retained and discharged real requests, not a new generic accepted wrapper at every call site. Keep DiagnosticAccepted as its current concrete product unless the proof demonstrates that replacing it removes more machinery than it adds. No new public type is needed for this design.

5.2 Source-free collection algorithm

When offering a Vec<ActionItemResult<Item>> to custody:

  1. Consume its members in their existing order.
  2. For attempted acceptance, use Item::retain_accepted; omit only discharged receipts, retain accepted values returned as Some unchanged in kind.
  3. Keep complete rejection, blocking, corruption, and untouched items.
  4. Return Exhausted only for an empty residual; otherwise return Retained.
  5. Perform no send, source admission, reinterpretation, or automatic retry.

Classification remains independent: retained acceptance is Accepted, ordinary rejection is Rejected, and corruption/untouched work is Corrupt. Driver must inspect interpretation status before custody compacts discharged values. A residual is not a complete historical success log. Do not reinterpret its absence of discharged receipts as evidence those effects never occurred.

The accepted-retention operation is idempotent on its retained values: once it returns Some, reapplying it must preserve that same value as Some. It cannot perform effects or consume authority that its result still promises to own. Re-offering a retained residual preserves it. A product with an earlier retained lane still offers a later source lane. If that later lane is admitted, the product returns Admitted with the retained sibling; after processing the source input, the next offer still returns that sibling. Source closure keeps the entire remainder. Preserve existing inner-before-owned SendLayer order and named product order.

Audit offer_source_in_order, ActionSettlement composition, Actors' send_product!, and generated/handwritten products. Change only machinery whose current implementation fails this law. Driver's current Retained path should need regression coverage, not diagnostic-aware production code.

5.3 Memory and retirement law

After any number of continuing turns, stored custody grows only with values whose ownership is still outstanding. Successful unit receipts and delivered diagnostics cannot create a growing retained history. Deliberately retained diagnostics do occupy memory until retirement; do not silently cap or drop them. Changing diagnostic disposition or bounded-retention policy is separate work.

At stop, source exhaustion, transition error, source closure, or interpreter failure, every retained value travels through the same typed retirement product as final behavior and runtime residuals. No actor must stop merely because it selected terminal custody for one diagnostic.

6. Creation, initialization, and publication

6.1 Commitment decision

Retain the current normative host commitment before effect interpretation law. Reject the proposed shortcut of moving a fallible address claim after consuming initialization actions. Select Address-owned hidden reservation and consuming publication as the runtime realization. This work is a dependency of complete startup acceptance, not code to place in Behavior.

The coherent sequence is:

exclusive fresh reservation, absent from logical resolution
  -> pure initialization exactly once
  -> private host and exact creator-local binding committed
  -> Established becomes true; host owns child and initialization work
  -> total initialization-effect interpretation exactly once
  -> initialization status recorded; source settlements processed lawfully
  -> continuing successful child may be publicly published
  -> ordinary mailbox transitions permitted

For atomic workers, initialization additionally supplies one activation permit; the aggregate's existing BeginActivation and activation result decide service availability. Worker initialization success is not application readiness. A stable proxy may be publicly present while its worker is unavailable, according to its existing service policy.

Established proves a fresh concrete child host and committed occurrence/ID binding with explicit CreationKind. It does not prove initialization effects accepted, endpoint publicly resolvable, child still live, activation finished, or service ready. A child may stop before the creator consumes that creation result. Success must contain EstablishedCreation::Installed; the existing nested rejected alternative must never be emitted as successful host commitment.

Bombay must separate its internal child-host commitment acknowledgement from the public spawn/publication result. Parent establish_child must not wait for public readiness as its evidence of commitment. Root spawning can continue to wait for publication, but its failure must return the full unpublished terminal custody. Use the existing host/binding/task ownership; do not add another host registry or recreate proxy state in a spawn service.

Correct Driver's three early terminal initialization branches to retire without calling public publish. The private commitment acknowledgement must already have transferred child ownership, so this does not strand a parent waiting for its creation result. Retain public publish only on the continuing successful path after required source-settlement processing. A source transition that stops or fails before that point also remains unpublished.

Replace SpawnError::from_local's unreachable settlement case with an owned unpublished terminal return, preserving the existing concrete local outcome: final behavior, all action settlements, admitted control/user inputs, activation work, descendants, and factual disposition. Do not project it to bare Ended(Completion) or a coarse reason while dropping the residual. The root consumer either receives that product or its exact typed terminal projection. The design-stage external fixture must compile this product before changing broad spawn signatures or adding projection bounds across callers.

6.2 Address reservation requirements

The Address owner must supply an affine reservation that excludes competitors without making the endpoint resolvable. Registration identity allocation, collision checks, and generation exhaustion happen before irreversible effects. Publication consumes that exact reservation without a second fallible claim or new generation allocation. Release and published lease retirement affect only their own generation; stale retirement cannot remove a later registration.

No endpoint reference granted by reservation alone proves a committed birth. The host and creator-local binding must exist before issuing Established. Private parent reports, exact child control, and lifecycle observation must work without public logical resolution. Public logical self-send during unpublished initialization gets the ordinary absent-address rejection; do not install a hidden resolver exception. Exact/private traffic can be admitted according to its capability, but must not run ordinary child transitions before initialization.

Prove bounded-capacity progress for nested creation and early child reports. Never wait for a parent's initialization to complete while that parent waits for the same child's public publication. If reservation cannot meet these requirements, stop the startup stage, record the counterexample, and revise this PRD before production; do not silently switch commitment semantics.

6.3 Ownership equation and complete outcomes

Before the pure fold, the interpreter owns the routed creation. After a successful fold and before commitment it owns current child + untouched Actions. After commitment the child host owns execution and its effects; after interpretation it owns current child + exact settlement + unfinished runtime work. These products are not interchangeable.

The outer ItemSettlement::Accepted(ChildCreationOutcome::...) records that the establishment port accepted ownership and returned an outcome. Only the inner Established result proves a birth; an outer accepted item containing initialization rejection or panic must never be counted as a successful child.

Event / milestoneCreation resultInitialization/terminal result and custody
Batch routing refusesExisting whole-batch rejectionNo child fold; unchanged batch and namespace reason remain owned.
Allocation/reservation refusesExisting item rejection with complete routed creationNo child fold; exact runtime allocation failure remains available where projected reason is coarser.
Pure fold returns ErrInitializationRejected { creation, error }Current child, exact error, original correlation/provenance; no Actions were returned and no binding committed. Release reservation.
Host refuses after successful pure foldHostRejected { creation, initialization, reason }Current child and untouched Actions only. Release reservation. No accepted effects, readiness, birth, or restart.
Host commitsEstablished with installed evidenceHost owns initialization once; later failure does not undo this birth.
Expected effect rejection after accepted prefixStill committed EstablishedInterpret independent later effects. EffectsRejected(EffectsRejected) report; exact accepted/rejected settlement and descendants stay with host. No public publication. Drain child.
Interpreter returns typed corruptionStill committed EstablishedEffectsRejected(InterpreterCorrupt) report; complete prefix, faulting request, untouched suffix, and runtime work remain owned. No publication.
Initialization selects Stop, all effects acceptedStill committed EstablishedSettle final effects, produce exact normal stop, never publish or run ordinary ingress; InitializeWorker resolves Stopped.
Initialization selects Stop with rejected/corrupt effectsStill committed EstablishedCorruption outranks rejection; either outranks stop for initialization classification. Preserve the stop decision in settlement and independent termination evidence.
Successful continuing initializationEstablishedRecord success, settle source custody, permit publication; later request can resolve ReadyForActivation once with its plan and permit.
Cooperative owner shutdown before child foldNo false commitmentReturn untouched creation using existing environment-failure projection; retain exact cancellation disposition in runtime custody. Do not relabel it as initialization failure.
Cooperative owner shutdown after fold, before commitmentHostRejectedReturn current child and untouched Actions with environment-failure projection, retaining cancellation disposition downstream.
Shutdown after commitment, before publicationCommitted birth remains trueClose publication/ingress, settle or retain accepted work, then exact cancellation/stop and complete retirement. Return plan/report if source has closed.
Child panics after commitment, before publicationCommitted birth remains trueAuthoritative panicked termination; no readiness or public endpoint. Preserve extant host-owned custody; apply the panic limits below.

A committed replacement is a fresh birth explicitly designated as replacement. Only commitment authorizes a creation-level restart diagnostic. Successful service replacement still requires the proxy's existing ready outcome. Neither an attempted replacement nor an uncommitted failure produces successful restart.

6.4 Pure-initialization panic and cancellation limits

A panic in the pure initialization fold is not C::Error, not an accepted initialization, and not HostRejected with invented empty Actions. The current creation sum lacks that distinction. The selected minimal extension is ChildCreationOutcome::InitializationPanicked { creation }, retaining the current routed child, ID, route, and kind. Mirror it as WorkerCreationRejection::WorkerPanicked { worker } when settling a worker; proxy creation retains the original generic settlement. It grants no actor capability, retry permission, or guarantee that a partially mutated child is safe to run again. It is a creation outcome, not a new aggregate control state.

Write a focused external panic witness before adding these variants. Bombay must catch the pure fold while the current child remains in an outer owned slot, release its reservation, and return this outcome. Do not downcast, erase, or put a panic payload in Behavior. Any exact runtime panic evidence belongs to the existing runtime termination reporting contract. Reconcile exhaustive creation matching and both public rustdocs in the same design stage.

Pure initialization is synchronous. Cooperative cancellation is observed before or after it, not by inventing a half-completed successful Actions value. During asynchronous effect interpretation, cancellation must preserve an already-owned transfer until it settles or is retained by the existing custodian. Aborting a task or dropping a future that owns the sole payload is not successful custody transfer.

The guarantee has a necessary limit: arbitrary Rust code can move an input into a local and panic, destroying that value during unwind. Neither a new enum nor catch_unwind can reconstruct it. Process abort and forced destruction of the owner likewise cannot promise recovery. Tests must distinguish (a) typed rejection/corruption with complete return, (b) cooperative shutdown with retained work, and (c) panic with truthful termination and recovery of extant outer custody. Never assert recovery of a payload already destroyed by arbitrary panicking user code. Panic after a transfer must not fabricate the original request or report successful receipt. If a runtime path loses extant custody merely by where it stores its task locals, repair that runtime path.

6.5 InitializeWorker is settlement observation

Accepting this request transfers the original plan to the already committed child's host. The host observes its actual initialization result, then calls resolve once. It must never invoke initialize, replay effects, or create a replacement child to satisfy this request.

Available evidence when the request is resolvedReport
Initialization corruptEffectsRejected(InterpreterCorrupt)
Initialization rejected/blockedEffectsRejected(EffectsRejected)
No initialization failure, exact termination already knownStopped with that exact stop
Successful continuing initialization, no terminal evidence yetReadyForActivation with original plan and one permit
Initialization still executingKeep the request/plan owned until an outcome is known; do not fabricate success

Failure evidence takes priority over a simultaneous stop. If readiness was already issued and termination arrives later, keep both facts; do not retract or issue a second initialization report. Ordinary observation and initialization observation are independent consumers of the same execution evidence. Neither may steal the other's notification. Store evidence in the existing typed child host, scoped to its concrete endpoint and retirement lifetime, not in a global cache or protocol registry.

A request arriving after child termination must still settle using retained host evidence. Closed source admission returns the complete report, including plan or permit, to retirement alongside the child's settlement. Missing typed host support is InterpreterFault::MissingCapability with the untouched request, not successful Stopped, empty evidence, or a fabricated mailbox rejection. Duplicate/foreign reports remain subject to the existing aggregate correlation rules and must not issue another activation permit.

7. Repository-wide impact and simplification

SurfaceRequired workWhat must remain unchanged in meaning
behavior/src/effects/sending.rsAccepted retention declaration; complete vector residual custodySourceActions transfer, interpretation order and static result shape
behavior/src/effects/actions.rsVerify creation/send custody joins; change only a failing joinCurrent pending creation-custody fixes and exact step
behavior/src/actor/creation.rsPrecise commitment docs; pure-fold panic outcomeFreshness, occurrence, ordered batches, owned failures
behavior/src/{lib.rs,effects/mod.rs}Curate only necessary public exports/docsNo runtime dependency, umbrella request trait, or new user syntax
actors/src/atomic/pool/assignment.rsConsuming settle and removal of independent receipt assemblyCustomer/job conservation, completion authority, retry order
actors/src/atomic/stable_proxy/operation.rsConsuming settle and private receipt construction; narrow interpreter seamSource, operation, creation, control, exact endpoint
actors/src/atomic/diagnostic.rsDeclare retained versus discharged acceptanceRoute-free terminal policy does not stop the actor
actors/src/atomic/worker/{mod.rs,initialization.rs}Panic rejection mapping; settlement-observation documentationExisting activation plan/permit and failure classification
actors/src/{lib.rs,atomic/mod.rs,atomic/stable_proxy/mod.rs}Curate the actual interpreter port and remove superseded exportsSmall application surface; no duplicate aliases for settlement mechanics
Atomic proxy, pool, supervisor consumers and proxy_creation.rsExhaustive panic outcome/custody handling after focused proofNo new aggregate engine, policy, or public constructor inputs
actors/src/send_product.rs, macros, handwritten equivalentsProve identical retention, order, and source progressionNamed products and inferred application syntax
Testkit, integration tests, compile fixtures, fuzz targetsAdd external ownership oracles and changed-sequence coveragePure models stay independent of interpreter implementation
Canonical docs and five actor catalogue/law documentsReconcile commitment, source-free custody, panic, publicationDistinct template policies and cardinalities
Bombay DriverContinuing-turn/mixed-custody regressions; remove publication on failed or stopping initializationOne generic driver; no diagnostic/proxy dispatch
Bombay local/launch/application runtime/child bindings/terminal projectionEarly private commitment, startup evidence, real leaf interpretation, full failure custodyActual delivery/tasks/observation owned by runtime
AddressExclusive hidden reservation, promotion, exact-generation releaseOne registration authority, no competing Bombay registry

Before migration, enumerate exhaustive creation consumers with:

rg -l 'ChildCreationOutcome::|WorkerCreationRejection::' crates --glob '*.rs'

Current production matches include atomic/pool/worker.rs, atomic/stable_proxy/worker/mod.rs, atomic/proxy_creation.rs, atomic/worker/mod.rs, atomic/fifo_pool/mod.rs, atomic/keyed_pool/{mod.rs,shutdown.rs}, and core creation dispatch. The same search includes integration tests, benchmarks, and fuzz targets; keep those in the migration ledger rather than treating a library-only build as complete. Paths prefixed atomic/ here are under crates/actors/src/.

Related request families must be checked: ordinary logical/exact deliveries, CustomerDelivery, PrepareWorkers, BeginActivation, observation, shutdown, parent reporting, timers, and RetirementBirths. They do not automatically need new APIs. BeginActivation must respect the existing started-before-plan-poll contract in the witness; no new activation framework is in scope.

The proposed reduction is specific: remove downstream envelope reconstruction, public independent receipt assembly, duplicate initialization execution, and startup panic/empty-residual assumptions. Keep one total settlement algebra, one source-custody traversal, and one Driver retirement path. Do not call the work code reduction if its measured production delta is positive.

After the blockers pass, a separate consolidation stage may compare repeated named-product traversal or request transfer code. A merge requires identical ownership, ordering, error, source, and retirement equations plus deletion of the competing mechanism. Similar field names and matching branch counts are insufficient. The five aggregate state machines are not a preapproved target.

8. External interpreter fixture

Add an isolated downstream Cargo fixture at tests/interpreter-contract/, with its own [workspace] and lockfile. It must not become a production workspace member or pull Bombay/Tokio into core. The fixture depends on the current candidate Behavior, Actors, Bombay Engine, Bombay, Address, and Communication graph. During development explicit path patches are permitted and recorded; CI/release uses immutable compatible revisions. A script rejects duplicate Behavior versions and mismatched sources using Cargo metadata. Do not accidentally test registry Behavior inside Driver against a different local Behavior in the fixture.

Use public exports only. Implement narrow real capabilities in this fixture where production leaves are still absent; final acceptance also runs through Bombay's completed production leaves. No cfg(test) access, test-only public constructors, copied Driver, fake task host, erased actor, or manually successful host receipt may substitute for that final run.

Required fixture files: Cargo.toml, Cargo.lock, README.md, test modules delivery.rs, custody.rs, startup.rs, shutdown.rs, and compile fixtures under tests/compile/{pass,fail}/. Group shared concrete test protocols in one support module only when they own real common protocol definitions. Use domain names in source; requirement IDs below belong only in documentation/manifests.

Use non-Clone, non-Copy plans, definitions, diagnostics, and completion authority. FIFO/keyed jobs implement Clone under their existing retry law; record the original and transferred allocations separately and require exact return of the retained original on rejection. Get requests from real FIFO/keyed/supervisor transitions. A second same-typed request provides a substitution adversary. Observe payload identity through owned unique values and final recovery, not invented IDs guessed from sequence arithmetic. An independent drop ledger may instrument payload lifetime but cannot supply authority or reconstruct missing payloads.

Deterministic control gates force close-after-resolution, settle-before-stop, stop-before-report, and source-close races. No sleeps or probabilistic timing. At each observable cut, each issued value is in exactly one allowed owner: aggregate, pending request, accepted destination, returned rejection/report, active runtime work, or terminal custodian. Final explicit discharge is recorded separately. Count conservation after every event, not just at shutdown.

9. Mandatory acceptance matrix

All rows run in debug and optimized builds where executable. Compile failures must fail for the named ownership violation, not unrelated missing bounds.

IDRequired scenario and oracle
T01Accepted assignment reaches real exact worker once; original receipt returns to source; completion is still separate.
T02Closed assignment and close-after-resolution return the exact original FIFO job, target, move-only completion authority, and original correlation. Settlement makes no copy; the pool's documented retry policy already cloned the worker payload. Source may recover/retry under that law.
T03Two same-typed assignment requests settle in either order without receipt exchange; external assembly and double settlement fail to compile.
T04Proxy start, replacement, and shutdown each use real private-control admission; accepted receipt identifies original operation, creation, and exact proxy.
T05Proxy missing binding, closed control, and close race return complete definition/plan/control and original operation/source. Wrong occurrence and forged receipt fail to compile.
T06Emit terminal diagnostic on a continuing turn, process at least three later turns, then retire; recover the exact non-cloneable diagnostic once. No premature drop.
T07Many successful ordinary receipts and delivered diagnostics leave no retained receipt history. A routed diagnostic rejection remains complete in terminal custody.
T08Mixed product: retained acceptance, source action, creation receipt, independent request. Both legal wrapper orders preserve order; source admission progresses; closure retains every remaining lane.
T09Typed rejection at every position still attempts independent later items. Corruption at every position preserves exact prefix, fault, untouched suffix. Source-free rejected/blocked values survive continuation.
T10Pure initialization rejection returns current move-only child and exact error, no actions, binding, publication, or successful restart.
T11Reservation/host refusal returns the appropriate untouched creation or current child plus complete untouched Actions. No effect is attempted.
T12Initialization accepts one effect, rejects the next, accepts an independent later effect; no rollback, no reconstructed Actions, no publication; complete runtime settlement survives to root.
T13Initialization accepts a prefix then reports corruption; suffix remains untouched and owned. Ready/activation cannot be manufactured.
T14Initialization stops with final effects; effects settle once, no ordinary event runs, no endpoint becomes public, and exact stop reaches observation and initialization consumers. Include stop plus rejection and corruption.
T15Initialization succeeds once; InitializeWorker arrives before and after completion and after termination. Correct report/plan/permit each time; no second initialization or activation authority.
T16Panic during pure initialization returns typed uncommitted panic outcome and extant child custody. Panic after commitment is exact termination, not creation rejection or a parent panic. Test stated unwind limits explicitly.
T17Cooperative cancellation before fold, after fold, during an in-flight effect, after commitment, and just before publication retains actual ownership and prevents false success.
T18Termination and initialization report arrive in both orders; independent observer still receives exact terminal evidence. Parent closes before each admission; full values reach root.
T19Nested child startup and early private reports progress with bounded mailbox capacity; no parent/child publication deadlock. Public logical self-send while unpublished has the documented rejection.
T20Address reserve/competing claim/resolve/publish/release races, registration exhaustion, and stale retirement preserve exclusivity, hidden visibility, and exact generation.
T21Shutdown during assignment/proxy/initialization/activation preserves already-admitted work and pending reports/plans through the real retirement barrier. Never-ready work remains explicitly owned; cancellation is not fabricated completion.
T22Ordinary creating actor and an atomic owner both work; FIFO plus fixed supervisor provide unrelated template witnesses. Test both Watch<ReceiveTimeout<B>> and ReceiveTimeout<Watch<B>> with meaningful observation and timing policies.
T23Fixed/dynamic supervision, proxy replacement, FIFO/keyed work execute through public Bombay applications after leaf integration. Acceptance cannot masquerade as ready/completed/restarted.
T24Handwritten/generated equivalent products, heterogeneous child occurrences, source closure and RetirementBirths preserve identical custody without structural application syntax.

Sensitivity proof: restore or simulate each original defect in an isolated candidate and demonstrate the corresponding test fails for that law. T06 must fail on the current unconditional Exhausted implementation even though immediate-stop tests may pass. T02/T05 must reach actual rejection after payload transfer; privacy-only compilation is insufficient.

Extend existing independent models and sequence targets for changed inputs, including fifo_pool_sequences, keyed_assignment_sequences, keyed_binding_sequences, and relevant lifecycle/catalogue sequences. Use Address's concurrency verification for reservation interleavings. Do not copy implementation matches into an alleged independent oracle.

10. Ordered implementation work packages

Each package starts with law, external syntax, failing regression, and reuse/ deletion ledger before production. Design and mechanical migration are separate. Do not silently make an unresolved design choice during migration.

PackageWork and prerequisitesCompletion evidence
P0 — Baseline and red witnessesPin merged/current trees, snapshot dirty changes separately, inventory every affected symbol, create external fixture and dependency-source check.Current-source D1–D7 evidence; focused failing ownership/retention/startup tests; exact anticipated change ledger.
P1 — Retained acceptanceImplement section 5 in core and diagnostic owner. Prove source-free failures and mixed product composition.T06–T09, T22/T24 focused witnesses; no diagnostic-specific Driver logic or ordinary receipt accumulation.
P2 — Complete deliveryImplement section 4, assignment first and proxy second; compare existing ports before publishing the proxy seam. Narrow old assembly API only after real witnesses pass.T01–T05; two same-typed concurrent requests; privacy, move, source and occurrence failures.
P3 — Startup ownership proofEstablish Address reservation and private child commitment witness; add pure-initialization panic outcome and smallest ordinary/atomic consumers; specify root unpublished return concretely.T10–T20; one ownership trace for every row in section 6; no consumed Actions in HostRejected.
P4 — Current caller migrationOnly after P1–P3 prove APIs, mechanically update all consumers, generated/handwritten products, tests, docs and runtime leaves.No new abstraction discovered; fixed/dynamic/proxy/FIFO/keyed checks and public syntax preserved. Discovery of new semantic plumbing reopens its design package.
P5 — Integrated runtime and releaseComplete actual Bombay leaf interpreters using proven contracts; run shutdown/activation races and all required gates; select immutable compatible dependency graph.T01–T24 on production runtime; complete terminal ownership at root; reproducible versions and command logs.
P6 — Optional consolidationSeparate follow-up after blockers are closed. Compare complete ownership equations and delete demonstrably repeated machinery.Independent law proof and measured deletion; no promise that the entire catalogue or Bombay runtime can be collapsed.

No package may claim complete integration from a local path-patched compile. P5 requires an immutable candidate graph and a coordinated release/pin plan. Version according to the actual API break; do not assume narrowing constructors or extending exhaustive public sums is patch-compatible. Release publication itself is separate from this documentation deliverable.

Required verification commands

Use the pinned toolchain through nix develop -c when Cargo is absent from the shell. In the Behavior repository:

nix develop -c cargo nextest run --workspace
nix develop -c cargo test --workspace --doc
nix flake check

The fixture must document and run:

nix develop -c cargo test --locked --manifest-path tests/interpreter-contract/Cargo.toml
nix develop -c cargo test --locked --release --manifest-path tests/interpreter-contract/Cargo.toml

Wire fixture execution into the authoritative CI gate; an isolated workspace is not covered by --workspace. Run applicable Bombay and Address gates too. Activate the three currently ignored Bombay local-publication regressions. Preserve absence while effects are pending and after rejection/corruption. The current successful test expects visibility after activate but before publish; move that successful visibility assertion to the explicit publication milestone selected here and add an absence check before publication. Record this intentional test-contract correction; never weaken the pending/failure checks. Log actual command outcomes and environmental failures separately. Focused proof comes before broad migration and repeated full-suite runs.

11. Architecture checkpoints and budgets

The target adds zero aggregate control states. The core acceptance method adds no new public type. The proxy port is at most one new interpreter trait; Address reservation is its own capability. The pure-fold panic extension adds variants to existing creation/rejection sums, not a universal startup framework. These are proposed limits, not measured implementation success.

Current aggregate top-level control sums relevant to review:

  • Proxy: Dormant, Starting, Ready, EmptyInitial, EmptyAfter, Replacing, ShuttingDown, Stopped (8).
  • FIFO: Constructed, Operating, Draining, Stopped, ForcedRetirement (5).
  • Keyed pool: Constructed, Operating, Retiring, Stopped, ForcedRetirement (5).

Do not pretend those counts measure fixed/dynamic state held in their owned member/entry products. Before each semantic experiment, write the complete control sum and every subordinate alternative for the aggregate actually changed. Record the exact current value each surviving alternative owns. A protocol result is not an additional aggregate state or dispatcher.

Every retained batch must have this record, before and after:

Required measurementRequired explanation
Aggregate control statesComplete domain sum, not just number
Subordinate state and result alternativesEvery retained value and the future decision needing it
Transition branchesSame counting method before/after; report measurement method
Production lines and modulesSeparate production from inline/integration tests and generated code
Public spellings/types/traits/variantsList additions and removals, including doc-hidden exports
Residue scanArrival history, repeated causes, false cardinality, nested transition authority, semantic booleans, structural user syntax
Contract cross-checkCanonical runtime/transition/layer contracts and all five normalized actor laws
ProvenanceEach new symbol linked to pre-edit law, failing regression, real consumers, and deleted/reused machinery
Dispositionpass or reopen; missing measurements mean reopen

The required cross-check documents are runtime settlement, transition algebra, layer laws, and the normalized proxy, fixed supervisor, dynamic supervisor, FIFO pool, and keyed pool laws. Review their ownership equations; historical representation names are not instructions to reintroduce removed machinery.

On reopen, remove only that experiment's production representation, record its falsifier in DEAD_ENDS.md, and return to the last retained design. Never revert pending user work. No blanket bounds, new no-op policies, hidden compatibility wrappers, default generics, erased futures, or visibility fixes may be introduced to silence compiler errors.

Expected Behavior design owners: the core sending/creation files, assignment, proxy operation, diagnostic, worker creation, their curated export surfaces, and focused tests. Runtime owners: local host, launch, child bindings, application capabilities, terminal projection, and Address registration. The implementation ledger must name the exact files and estimated deltas before editing; this cross-repository scope will likely cross the repository's review thresholds and must be presented as such.

Per AGENTS.md, more than 15 changed files, more than 500 net new production lines, or more than three new public types requires explicit expanded-scope authorization before further production edits. Count cumulatively across packages; do not reset counts per commit. Report unrelated pre-existing changes separately. This PRD does not waive that rule or mark an experiment retained.

12. Definition of done and prohibited shortcuts

The blockers are complete only when:

  1. All T01–T24 rows have concrete evidence against one candidate dependency graph; external compile and real runtime results are reported separately.
  2. Every ownership row in sections 4–6 has an executable witness and a truthful public contract; no startup outcome hits a known unconditional panic branch.
  3. Generic custody retains requested evidence across continuing turns and retires it once; discharged receipts do not accumulate.
  4. Initialization occurs once, creation commitment is explicit, and unpublished failure returns real custody instead of pre-interpretation fiction.
  5. Complete source/API/doc migration and required gates pass; ignored tests or temporary source patches are not counted as completion.
  6. Each retained batch passes the drift/provenance checkpoint and reports its actual capability additions separately from deletions.

Reject any patch that makes reconstruction fields public, clones jobs to recover rejection, stores all receipts forever, treats diagnostics specially in Driver, reinitializes a worker, converts consumed effects into empty Actions, conflates admission with completion, discards startup residuals after logging, or moves runtime mechanics into pure Behavior. Also reject arbitrary state-machine unification justified solely by hoped-for line reduction.

13. Review evidence and reproducibility

The review traced current core action/item/creation composition, assignment and proxy request ownership, diagnostics, worker startup, proxy/pool/supervisor consumers, named send-product custody generation, testkit limitations, canonical and normalized laws, and adjacent Bombay launch/Driver/host interpretation. This is a holistic review of these contracts, not a claim that every unrelated catalogue branch was executed or proved redundant.

Current physical source inventory (includes inline tests/comments, so these are review-surface counts rather than production-only budgets):

Cratesrc Rust files / linestests Rust files / lines
Behavior10 / 6,76415 / 3,796
Actors125 / 57,86044 / 35,604
Macros1 / 1,49910 / 255
Testkit2 / 17331 / 8,112
Mutation gate1 / 6120 / 0

Nested fuzz targets, benchmarks, and nested fixture workspaces are additional verification surfaces, not included in this table.

Current-source SHA-256 fingerprints, captured before this document revision:

File under crates/SHA-256
behavior/src/effects/sending.rsa768908396a6878be079290c4dda02b39297449ad34f3e48c349880dacc6c468
behavior/src/effects/actions.rs189cb846f51c0b07d38789cf1bca5b291b73e86c58b9428063ab9bf61db78ae9
behavior/src/actor/creation.rs9d490247c4e1e3b7252643bb262249fadf14c82b774d09290d31259127a7b181
actors/src/atomic/pool/assignment.rs719e30c321f234ebbb1777c3c4fcb3c547a0a54111b4556a1564732972c14903
actors/src/atomic/stable_proxy/operation.rs55fdb78ee174ce1b772fb7fd179600004411c3b07a2aa505207fd22e0a175df5
actors/src/atomic/diagnostic.rsef8f9f873284db7a534ad6536a77cd5a675f91e963b56674aa7f17fa2fe85b09
actors/src/atomic/worker/initialization.rs09487c21e7368911242aceaf202fa81f4627037bd6f21a9f76bb56e42a46a3f6

The adjacent downstream record already contains debug/optimized diagnostic reproductions and the ignored visibility failure. Those are prior evidence, not a claim this review reran the full runtime.

This review also compiled a disposable external Cargo crate with path dependencies on the current Behavior and Actors source, using Cargo 1.95.0. Its non-cloneable Diagnostic(Box<str>) was placed in Vec<ActionItemResult<DiagnosticAction<Infallible, Diagnostic>>> as Accepted(DiagnosticAccepted::Terminal(value)). Calling the public SourceSettlementCustody::<(), ()>::offer_next_to_source returned Exhausted. The test demanding Retained failed with exactly terminal diagnostic was classified as exhausted in the debug build. This verifies D3 on the current code; it is not the T06 real-Driver witness. The disposable probe is outside the repository and is not a retained test.

Documentation validation: mdbook build docs passed, the four published-doc checker unit tests passed, the rustdoc-import scan passed, and acceptance-ID, work-package, navigation, and diff-whitespace checks passed. Full runtime verification of the proposed implementation remains P1–P5 work.

The reviewer also started nix develop -c cargo nextest run --workspace, nix flake check, and an optimized build of the disposable diagnostic probe. These did not produce final test verdicts during the review and were explicitly interrupted by the reviewer. They are unverified, not passing checks and not demonstrated code failures. The standalone rustdoc-error-code script also could not run outside the Nix environment because Cargo was absent from that shell; its authoritative flake invocation is included in the unverified full gate. The optimized diagnostic failure recorded in the adjacent downstream review must not be presented as a newly completed optimized run against this source.

Task-attributable implementation delta for this PRD: production +0 / -0 / net 0; retained tests +0 / -0 / net 0; public types +0 / -0. No production experiment is marked retained by this documentation change.

Interpreter contract implementation ledger

This ledger records implementation evidence against the separately maintained ownership and startup PRD. It does not change that specification or treat a scripted host as a production interpreter.

Merged Behavior candidate, 2026-09-30

The release branch merged current main at 835cf8d into the repaired Behavior candidate at bd613ae. The merge retained both ordinary direct dependency and facade-first Actors macro witnesses. Its five macro-resolution fixtures passed, followed by all ten local aarch64-darwin Nix checks and the external interpreter fixture in debug and optimized builds. The user's revised PRD was copied from the original worktree into this release branch, then T02 was clarified to preserve FIFO's existing clone-and-retry law. The original uncommitted file remains untouched.

The external workspace now has a README and a Cargo-metadata guard. The guard requires one local resolved package for each of core Behavior, Actors, and macros, rejecting a duplicate or registry copy of these crates. It passed on the merged candidate. It does not assert that the later Bombay/Address graph is immutable or integrated. The retained-diagnostic witness now carries one non-cloneable value across three later source-free offers, adding a discharged diagnostic on each offer; each resulting residual contains only the original terminal value. Debug and optimized tests pass. This strengthens the Behavior-side T06/T07 law, while the real Driver retirement remains P5. The precommit creation fixture also now rejects pure initialization with a non-cloneable child and error, verifies that into_actor refuses to issue an established capability, and returns the exact current child, route, ID, kind, and error allocation. Debug and optimized tests pass. This is the Behavior ownership shape for T10; the real reservation and publication trace remains downstream. The external mixed-product fixture now combines retirement creation custody, an accepted terminal diagnostic, a live source request, and an independent rejection. It exercises two SendLayer orders, requires source admission to progress past retained siblings, and verifies that closed admission returns every lane and the continuation verdict. The focused tests pass in debug and optimized builds. This is the Behavior-side composition portion of T08/T24, not a real Driver trace. The canonical adapter contract was corrected to distinguish private host commitment and EstablishedCreation::Installed from later effect settlement and public resolution. It now states that ordinary rejection continues independent effects while corruption owns an untouched suffix. This is a documentation correction to the existing Behavior algebra and the PRD's selected startup order; no runtime publication implementation is claimed.

Before/after for this evidence-only batch: aggregate control states and subordinate alternatives unchanged; production transition branches and production lines unchanged; one fixture README and one graph-check script added; one CI step and three external test files changed; public spellings unchanged. The terminal value remains the sole future-needed residual. No arrival-history state, duplicate cause, cardinality assumption, nested transition authority, semantic boolean, or structural caller syntax was added. Cross-checks: actor-transition-algebra.md, atomic-runtime-settlement.md, behavior-layer-laws.md, and the five normalized actor-law documents. Disposition: pass for this Behavior-side evidence batch. The PRD's real runtime acceptance matrix is still open.

PRD packageBehavior-side dispositionDownstream dependency
P0Current source fingerprints, red ownership regressions, isolated external fixture, and single-source graph guard recorded.Add immutable Bombay/Address/Communication revisions to the same graph for P5.
P1Core retains only outstanding accepted values; terminal diagnostics survive repeated turns and ordinary receipts discharge; both wrapper orders and closed source return pass.Real Driver continuation and root retirement.
P2Assignment and proxy requests consume their lower capability, keep private correlation, and return complete actual payloads on rejection; two same-typed requests and compile denials pass.Real Communication and exact private proxy-control admission, including close races.
P3Core returns exact pure rejection, uncommitted panic, and untouched host refusal; worker panic maps to its owned rejection and public docs distinguish commitment from publication.Address reservation, private host acknowledgement, effect settlement, termination, and public publication.
P4Behavior-owned aggregate consumers, generated/handwritten products, exports, tests, and canonical docs use the retained contract; workspace and external fixture gates pass locally.Bombay and Address callers migrate after this crate release.

These dispositions cover the Behavior column of the PRD's scope table. They are not claims that the cross-repository P0–P5 packages or T01–T24 runtime matrix are complete. P5 and A17 remain open until the released dependency graph runs the real leaf interpreters.

P0 snapshot, 2026-09-29

Behavior is at 605d0634644a435f4bba31ce1768253abcafe23e on codex/repository-quality-repairs. The PRD is an uncommitted user edit and is excluded from this snapshot. The isolated Bombay worktree is at f462b8ec25a4cc43aabf89fe448c09e3da9d12b7 with pending local changes; the Address checkout is at 87f7af4fd67671bbcf05c59f5da687b40ce7ba98. Neither adjacent repository was edited for this ledger.

File under crates/Current SHA-256
behavior/src/effects/sending.rs4e8c578ae4a99383471fea3f7fc579f1c066d249505ae242fad9e47b952e09c2
behavior/src/effects/actions.rs189cb846f51c0b07d38789cf1bca5b291b73e86c58b9428063ab9bf61db78ae9
behavior/src/actor/creation.rsc47b085f147ce1443f634b3527a426030ec165923c0e833b8bb1cbb0d610172f
actors/src/atomic/pool/assignment.rs308f3d4a78e06be1e027a1a3410ff374a72c2eb4897bcfbc278425cc1ecbbf8c
actors/src/atomic/stable_proxy/operation.rsfda908e08c7a285d6b7e32555402ea9c8aac32f45f06a2dc631e1efd0b4220f3
actors/src/atomic/diagnostic.rs8a36bdb2d6f28d5279c52a131fdf999f881ec7394f81a89982e686813538f8e6
actors/src/atomic/worker/initialization.rs09487c21e7368911242aceaf202fa81f4627037bd6f21a9f76bb56e42a46a3f6
PRD defectCurrent-source resultRemaining proof
D1 assignment ownershipAssignWorker::settle consumes the request and returns its original receipt or complete request; decomposition and reconstruction are crate-private. External acceptance/rejection and compile-fail fixtures pass.Real worker admission, two concurrent same-typed requests, and production source return.
D2 proxy ownershipProxyOperation::settle uses ProxyControlAdmission; operation decomposition is test-private and the receipt constructor is private. External privacy fixtures pass.Real start/replacement/shutdown admission and failure races.
D3 retained acceptanceGeneric ActionItem::retain_accepted compacts discharged receipts; diagnostic ownership opts into retention. External custody fixtures pass in both profiles.Real Driver continuation and retirement with the exact retained value.
D4 startup ownershipHostRejected still requires untouched initialization Actions. InitializationPanicked already exists and has an external pure-fold custody witness.Host commitment and every post-commit failure outcome through the real runtime.
D5 child commitmentIsolated Bombay establish_child still awaits spawn_owned_with, which waits for publication. A pre-publication end can still reach a panic branch.Private commitment acknowledgement and exact unpublished terminal return.
D6 hidden address reservationAddress now exposes try_reserve and consuming Reservation::publish; the isolated Bombay LocalEnvironment::prepare uses it.Runtime interleavings, bounded nested progress, and immutable dependency graph.
D7 premature publicationThe isolated Driver now calls publish only on the continuing initialization path after pending settlements progress; the early terminal branches no longer call it.Production startup rejection/corruption/stop traces and public-resolution absence.

The fixture at tests/interpreter-contract passed all 12 baseline test functions in debug and optimized profiles. Its assignment host and startup panic witness are local interpreters, so they do not close the production runtime matrix. The fixture is already wired into .github/workflows/checks.yml in both profiles. A clean Nix flake check at the Behavior snapshot passed eight available aarch64-darwin checks, including 843 optimized Nextest tests.

Next ownership proof

T03 focused law before extending the fixture: two independent FIFO pools can have same-typed worker deliveries outstanding at once, even when their creator-local child IDs are numerically equal. Settling those deliveries in reverse order must return each opaque accepted receipt to its originating pool. Both pools must continue without a foreign-receipt diagnostic, and each later worker completion must produce exactly its own customer outcome. The existing AssignWorker::settle and FIFO receipt correlation supply the lower-order behavior; no new production representation is proposed. The external regression now passes in debug and optimized profiles. It uses two separate pool instances with equal numeric child IDs, settles their same-typed requests in reverse order, rejects any diagnostic or early customer outcome, and checks both later completions. This is a focused T03 witness, not a production transport witness.

T01/T02 pointer witness correction: the previous fixture recorded the address of a Box<str> handle and compared it with the address of its heap payload. Those different addresses could not prove job custody. Requiring equality first made both baseline assignment tests fail, exposing the weak assertion. Source inspection then found FifoPool requires Job: Clone and clones the queued payload into Assignment; the pool retains the original so it can return it if delivery fails. The corrected fixture records the worker payload's actual heap address, requires it to differ from the original, and requires a rejected assignment to return the original address. The concurrent test checks both copied worker payloads in reverse settlement order. No production symbol or actor transition changed.

The earlier PRD's T02 requirement for a move-only job is not proved by this FIFO fixture: Box<str> implements Clone, and the current FIFO bound rules out a non-Clone job. The full ownership equation must be revisited before claiming T02 complete; a test using a cloneable value cannot certify a move-only law. This is a real policy conflict, not just a missing test: FIFO's dispatch clones queued.customer.payload into Assignment while retaining the original in AssignedJob. On accepted delivery followed by a worker stop, Interruption::Fail returns that original as ReturnedAssigned, and Interruption::Retry requeues it. A single non-Clone job cannot be both transferred to an independently executing worker and retained by the pool for those later paths. The public pool is the only current producer of this exact assignment request besides the similarly clone-bound keyed pool. A future move-only witness therefore needs a changed post-acceptance return/retry law or a distinct lawful producer; merely changing the Job: Clone bound would make the existing transition impossible. No such policy change was made here.

The revised T02 preserves FIFO's existing clone-and-retry law. It requires a rejected delivery to return the pool's exact original job and affine completion authority without another settlement-time clone. The pointer witness proves this Behavior-side distinction; the real close-after-resolution runtime trace remains open for Bombay integration.

The remaining work is to establish the exact pre-commit versus post-commit ownership equation with a production host witness, then cover PRD T10–T21 and the catalogue composition cases. Any Behavior production-shape edit needs a focused failing law regression and aggregate-drift record first. Real Bombay changes are outside this Behavior branch while the instruction to leave that repository untouched remains in force. A local or path-patched compile does not close P5 or audit item A17.

T11 Behavior-side host-refusal custody, before fixture edit

The derived Bombay pre-commit law says a host refusal after a successful pure initialization returns the current child and the complete untouched Actions; no request has crossed the interpreter boundary. The existing public ChildCreationOutcome::HostRejected already carries those values, but the action_interpretation host-rejection case supplies Actions::cont() and cannot detect loss of a pending send. The next external fixture will run a move-only child's pure initialization, retain two ordered move-only sends, then construct and decompose the public host-rejection outcome. It will check the original allocations, route, creation ID, kind, send order, and continuation verdict. No production type, bound, host operation, or state change is proposed. This proves the Behavior-side ownership equation only; a real reservation refusal and non-interpretation trace remain mandatory for T11.

The external startup_host_rejection fixture now passes in debug and optimized profiles. OwnedText has no Clone implementation. The test checks that pure initialization moves both pending sends into Actions, then a host refusal returns the mutated current child, both exact send allocations in order, the original route, creation ID, birth kind, and Continue decision. The first version adds 116 test lines and zero production lines, types, states, branches, modules, or public spellings. No arrival history, repeated cause, false cardinality, nested transition authority, semantic boolean, or positional caller syntax is introduced. Cross-checks: the actor transition algebra and PRD section 6.3. Disposition: pass for the external Behavior-side custody witness. T11 remains open because the fixture does not own an Address reservation or a production child host and therefore cannot prove that a real host attempts no effects after refusing commitment.

Creation-lane extension, before edit: the first fixture observes two sends and Continue but leaves the creation leg empty. A host refusal must also return a staged nested creation untouched. Extend the same fixture with one move-only nested child, check its exact allocation, ID, and birth kind after decomposing HostRejected, and keep the existing ordered-send assertions. This is a test-only strengthening of the same derived law; no actor or interpreter type changes.

The extension passes in debug and optimized profiles. Grandchild owns a separate non-Clone value; its staged request stays in the returned creation leg with the exact allocation, nested creation ID, and birth kind. The fixture now has 157 test lines and checks sends, creation, and next-behavior decision together. Production state, branches, modules, and public API remain unchanged. The nested child is current data required for a possible later commit, not arrival history; no duplicated cause, false cardinality, nested aggregate authority, semantic boolean, or positional caller syntax is added. Cross-checks remain the actor transition algebra and PRD section 6.3. Disposition: pass for the Behavior-side complete-actions witness; T11 still requires the real host refusal and absence of effect attempts.

Atomic actor essence and clean-room boundary (engineering record)

Status

This document defines a non-production falsification and model experiment. It is intentionally smaller than the existing atomic-actor catalogue. It may test whether a simpler template state machine and ordinary authoring surface can satisfy selected laws, but it does not authorize production actor types, change implementation status, establish catalogue parity, or permit migration.

atomic-actor-solution.md remains the production design authority. Its foundational prototype dependency order and coverage matrix remain binding for production implementation. If this experiment falsifies that order or supplies a replacement law, the solution, coverage matrix, retained-core decision, and research audit must be updated together before any production edit uses the result.

No Rust API is selected here. Capitalized names in equations name semantic states, not authorized public types.

Why this extraction exists

The detailed documents contain important discoveries, but they currently mix four different designs:

  1. the irreducible actor transition algebra;
  2. interpreter settlement, hosting, and lifecycle mechanics;
  3. the identity of each reusable actor template; and
  4. a maximal catalogue of policies and failure handling.

That mixture makes a local template change appear to require a universal activation service, a dependency-aware action language, recursive terminal lifting, residual root ownership, typestate builders, and every final policy at once. It recreates the conditions for compiler-driven design: a compiler error in one layer appears to authorize another wrapper, path, marker, alias, or associated type in every other layer.

The clean-room experiment begins from the semantic identity of each actor and tests one independently stated policy at a time. This is an experimental ordering, not a replacement production dependency order. An omitted policy is recorded as outside that experimental slice; it is never represented by a no-op callback, dummy route, default generic, or placeholder variant. A slice that omits a foundational solution law cannot count as implementation evidence for any coverage row that depends on that law.

Authority labels

Every law used by the experiment is labelled with one of these authorities:

  • Actor-model law — required by the actor semantics used by Bombay.
  • Bombay derivation — a typed construction used to realize an actor-model law without effects inside the behavior fold.
  • Template law — the defining contract of one reusable actor.
  • Policy choice — one deliberately selected answer where actor research does not prescribe a result.

The primary actor reference is Agha, Mason, Smith, and Talcott, “A Foundation for Actor Computation”. Its actor language identifies asynchronous send, fresh actor creation, and become as coordination primitives, and makes an actor's current behavior a deterministic function of the messages it has received. Agha's 1986 monograph is the foundational source for the open, dynamically reconfigurable actor model.

Those sources do not define supervisors, restart strategies, worker pools, readiness handshakes, delivery-rejection APIs, shutdown deadlines, fluent builders, or Rust effect products. Those are Bombay template or policy laws and must be presented as such.

Irreducible actor boundary

The clean-room experiment evaluates templates through the repository's locked equation:

initialize : Behavior -> Transition
receive    : (Behavior, one Communication) -> Transition

Transition = Communications
           * FreshCreations
           * (NextBehavior | Stop)

This means:

  • Actor-model law: an actor reacts using only its local behavior and one received communication.
  • Actor-model law: a reaction may send communications to known actors, create fresh actors, and designate its next behavior.
  • Bombay derivation: Behavior is a deterministic, directly testable fold and Actions is the explicit typed representation of those consequences.
  • Bombay policy: initialization is a separate fold interpreted before the first mailbox communication.
  • Bombay policy: normal termination and controlled transition rejection are explicit results even though they are not part of Agha's primitive three-operation presentation.

The executable prototype must implement the real Behavior trait and return the real Actions type from crates/behavior. A smaller local algebra may be used only as an independent model oracle whose vocabulary and transitions are kept separate from the executable prototype. Passing against a local algebra is not evidence that a template composes with Bombay's actor contract or that the interpreter can realize its effects.

Scheduling, allocation, endpoint installation, clocks, observation, transport, and effect settlement are interpreter operations. The fold may request them through a typed effect, or later receive a typed fact about them, but it may not perform them.

Actions is not a transactional promise across actors. Atomicity means that one local fold chooses one next state and one complete effect value. It does not mean that several messages are delivered atomically, that emitted effects succeed, or that a later rejection rolls back the source transition.

What makes a template atomic

An atomic actor template is one standalone behavior with:

  • one coherent domain responsibility;
  • one private exhaustive state sum;
  • one closed input sum containing public commands and exact runtime facts;
  • one explicit Actions product containing only effects that actor can emit;
  • one initialization transition;
  • total transitions for every state/input pair; and
  • no dependency on another wrapper to complete its own lifecycle law.

An atomic template may create another atomic actor. That is topology, not behavioral decomposition. For example, a fixed supervisor may own stable proxies, but its supervision decision is still one direct fold; it is not a stack of Supervise, relay, fleet, and positional-ingress wrappers.

A generic wrapper remains appropriate only for a genuinely orthogonal same-actor transformation such as stashing or a receive timeout. Adding a wrapper must not be necessary to understand a supervisor or pool's internal ownership.

The common semantic spine

The templates share laws, not a universal runtime state machine.

Ownership follows the phase

Every owned value has one visible owner in each phase. The important boundary is emission of an action:

ActorOwns(value)
    -> action not emitted: actor can reject and return value
    -> action emitted:     action/interpreter owns value
    -> settlement fact:    actor owns the returned result or exact capability

A cancellation or rejection may return a worker definition, job, result, or request only if that phase still owns it. No later state reconstructs the value from an id, clones it to escape ownership, or claims to return a value already moved into an action.

Creation is fresh and staged

  • Actor-model law: actor creation allocates a fresh actor. Changing the behavior of an existing actor is a different operation.
  • Bombay derivation: a behavior emits a staged create request correlated by a creator-local value, then receives an accepted or rejected creation fact.
  • Bombay policy: the accepted fact carries the exact installed capability needed by the creator. A correlation value is not an actor identity and a collision is rejection, never replacement.
  • Template law: replacement means creating a fresh successor and carrying explicit predecessor provenance. It never means overwriting an address.

The minimal lifecycle equation is:

OwnedDefinition
    -> CreationEmitted
    -> Installed(exact incarnation) | CreationRejected(complete request)

Installed
    -> Ready(exact incarnation)      when the template requires readiness
    -> Stopping(exact incarnation)
    -> Stopped(exact terminal fact)

Installation and readiness remain different facts. The first experiment may attempt to express readiness through ordinary typed protocol composition, but it must prove the complete authority chain:

  • which exact capability authorizes production of Ready;
  • which actor or interpreter owns that capability in every phase;
  • how Ready is correlated to the exact installed incarnation and one non-reused activation attempt or generation;
  • which explicit Actions effect initiates asynchronous activation work;
  • who owns the activation plan and exact incarnation while that work is in flight;
  • how accepted, rejected, stopped, cancelled, stale, duplicate, and late outcomes settle; and
  • why application code and an unrelated worker cannot forge readiness for the incarnation.

Injecting a typed Ready value directly from a test is model input only. It does not falsify the need for an activation capability or demonstrate an interpreter path. A universal activation plan, permit, task, authorization ticket, or hydration service remains unselected by this experiment until the ordinary-protocol attempt either proves this complete chain or fails with a focused compile/interpreter witness. The production solution's existing activation blocker remains authoritative meanwhile.

Correlation and provenance are exact

Facts are accepted only for the exact outstanding operation and incarnation. Role, key, address reuse, sequence adjacency, or arrival time cannot substitute for provenance. Stale, duplicate, foreign, and contradictory facts are explicit outcomes that preserve their owned data and leave valid state unchanged.

Private operation, incarnation, timer, assignment, job, completion, and binding correlations may be distinct types. Their constructors belong to the actor or test interpreter. A type is added only when it prevents a demonstrated invalid exchange; “the compiler needs a different name” is not evidence.

Acceptance, realization, and termination are separate

These facts must never collapse:

request admitted
effect accepted by interpreter
actor installed
actor ready
operation completed
outcome delivery attempted
actor terminated

Each template uses only the distinctions observable in its contract. A dynamic StartAccepted does not mean Started; a pool Accepted does not mean Completed; emitting a lifecycle report does not mean its destination received it; and a terminal report is not proof that its source has stopped.

Shutdown closes ownership

Shutdown is a typed input, not ambient cancellation. It closes new admission, extracts or returns values that cannot complete, and resolves every actor or creation still owned by the template before stopping. Duplicate shutdown does not duplicate effects.

The initial experiment selects one complete policy: wait for all owned actor facts. Deadline retirement, forced transfer, uncancellable external work, and residual root-run ownership remain a separate interpreter experiment. They are not encoded as flags or dummy variants in each template.

Retained state is bounded by a domain rule

Every table, queue, correlation set, and tombstone family needs a capacity or retirement law. “Keep it forever for stale detection” is not accepted. Old facts are made harmless with non-reused correlation and generation evidence, not unbounded historical state.

The five template identities

The following table is the catalogue essence. Policies may enrich a row, but they may not change the row's responsibility.

TemplateUnique responsibilityState it must ownDefining invariant
Stable proxyPreserve one public service identity across fresh worker incarnationszero or one exact worker incarnation, one install/replace operation, readiness, and drainOnly the exact ready current incarnation receives service commands; replacement never reuses an actor identity.
Fixed supervisorPreserve an ordered, declared role topology under a selected recovery policyone member state per declared role, exact stable-proxy ownership, and one recovery decisionOne immutable topology snapshot prepares admission; its membership partition, correlations, prepared ownership, and budget commit together, while participant realization resolves independently.
Dynamic supervisorManage a bounded set of keyed stable services through explicit operationskeyed entries, fresh entry generations, operation ownership, exact stable proxies, and retirementA key is management identity only; reuse after retirement creates a fresh generation and old facts cannot affect it.
FIFO poolOwn a fixed worker set and one customer obligation for each admitted jobworker lifecycle, FIFO backlog, active assignments, completion authority, and customer routesNo job is both queued and assigned; each admitted job has at most one terminal customer outcome; older serviceable work cannot coexist with eligible idle capacity.
Keyed poolAdd stable future-admission affinity to direct worker ownershipindependent direct-worker lifecycle, one obligation per accepted job, bounded key-to-role bindings, and per-role queuesSelection is retained at admission; rebalance/unbind changes future admission only and never retargets accepted work. There is no global backlog or worker-selection cursor.

Stable proxy

The proxy is the first template because both supervisors depend on its one atomic report boundary. Its minimum complete contract covers:

  • empty construction;
  • initial installation;
  • exact readiness before routing;
  • command return while unavailable;
  • spontaneous worker stop;
  • replacement by fresh creation;
  • overlap, stale fact, and creation rejection; and
  • shutdown during every live phase.

The owner receives one flat report sum. It does not reconstruct readiness from separate creation and stop observations. Service clients cannot address the owner-control protocol.

Fixed supervisor

The fixed supervisor owns semantic roles and stable proxies. It does not own application children and it does not convert a role into a nonce or address. Recovery eligibility, strategy, budget, and release timing are separate policy dimensions. They should first be implemented as local, exhaustive values in the fixed supervisor. A shared recovery abstraction is extracted only after a second direct actor demonstrates the identical transition law and the extraction deletes code.

The essential recovery transaction is:

observe exact terminal fact
    -> classify eligibility
    -> select roles from an immutable ordered snapshot
    -> prepare every replacement and fallible correlation
    -> admit or reject the complete decision
    -> commit member states and Actions once

Dynamic supervisor

The dynamic supervisor is not a fixed supervisor with an optional role list. It owns bounded keyed membership and explicit Start, Replace, Stop, Query, and retirement operations. Request replies describe admission; a separate durable route, if selected by the experiment, owns later lifecycle facts. Cancellation is added only with an exhaustive ownership table showing which phases still own and can return the submitted worker.

No fixed factory, restart strategy, restart budget, or no-op policy belongs in this template.

FIFO pool

The pool creates and observes workers directly. A stable proxy is unnecessary because customers address the stable pool, not individual workers.

The pool retains the customer destination and issues opaque completion authority with each assignment. The worker may consume an assignment to form a completion, but cannot choose or substitute the customer. Completion must match both the issued authority and exact worker incarnation.

Retry, if selected, is explicitly at-least-once execution. The pool retains the canonical customer obligation and a retryable payload while the worker owns an execution value. This is one semantic obligation represented by multiple Rust values, not an exactly-once side-effect claim.

Keyed pool

The keyed pool is a separate direct fold sharing only proven value laws with FIFO. A submitted key is mapped to a semantic role by one concrete selector; the selected role and fresh binding generation are retained as opaque admitted evidence with accepted work, while the binding alone owns the key. Per-role backlog and binding capacity are different bounds. Keyed pooling has no global backlog, circular worker cursor, or cross-worker serviceability law.

Rebalance and unbind use exact absence/generation expectations and affect only later submissions. Admission-created bindings require accepted work; management may explicitly bind an absent key. Absence has no stored entry, a role-changing rebalance issues a fresh generation, and a same-role rebalance preserves the current generation as an accepted no-op. Worker replacement keeps role affinity without keeping an address. Committing permanent role unavailability returns that role's work once and removes every binding to it; temporary recovery retains bindings.

Concerns deliberately outside the first falsification slices

The detailed documents contain candidate answers for the following concerns. The experiment may omit them from an early model or focused falsification slice because they are not part of a template's identity:

  • a universal activation plan/permit/request/fact protocol;
  • a global activation-authorization limit shared across owners;
  • per-item delivery settlement with source/host fallback;
  • transitive settlement priority before later mailbox traffic;
  • creation-scoped dependency bundles for every child operation;
  • total terminal projection through arbitrary heterogeneous wrapper stacks;
  • deadline retirement and residual root-run ownership;
  • final builder syntax and one typestate marker per configuration axis;
  • wrapper-depth diagnostic budgets; and
  • catalogue-wide delivery-rejection migration.

Each remains a production prerequisite wherever the solution and coverage matrix say it is. Omitting one limits the result to model/falsification evidence; it does not make a dependent actor implemented. The experiment may propose a simpler replacement only after a focused compile/interpreter witness and composition through two unrelated actors without caller plumbing. That proposal changes no production authority until all governing documents are updated together.

Delivery failure deserves special care. The actor model specifies asynchronous send and fairness assumptions at the semantic level; it does not prescribe Bombay's capability-level transport rejection API. The clean-room folds must preserve emitted values in the real Actions. Until accepted and rejected interpreter traces prove the selected settlement law, those folds remain non-production evidence and cannot satisfy dependent solution rows.

Clean-room crate method

The temporary crate must not import crates/actors, its protocols, aliases, builders, macros, tests, or helper state. Its executable prototypes must depend on crates/behavior and implement the locked Behavior/Actions boundary. A tiny local algebra is permitted only in tests as an independent model oracle and must never be adapted into executable evidence or a second actor contract.

The crate is developed in this dependency order:

real Behavior/Actions smoke witness + independent model vocabulary
    -> stable proxy
    -> fixed supervisor
    -> dynamic supervisor
    -> FIFO pool
    -> keyed pool

For each step:

  1. Write one plain-language law and a complete state/event/ownership table.
  2. Write the smallest pure-fold regression that fails because the actor does not yet exist, using domain vocabulary only.
  3. Add the private state sum and public protocol before transition code.
  4. Assert the complete real Actions result, including empty lanes and next verdict.
  5. Add stale, duplicate, overlap, rejection, and shutdown cases before adding another policy.
  6. Add deterministic accepted and rejected interpreter traces proving creation/effect order and retained ownership.
  7. Add compile failures only for actual capability violations.
  8. Audit every new prototype symbol against its pre-edit law and regression.

No common helper is extracted on first use. On second use, compare the two ownership and transition equations. Extract only if they are identical, the new abstraction owns a semantic law, and total prototype source decreases. Similar variant names are not enough.

Questions the experiment must answer

The clean-room crate exists to answer these questions with code rather than another speculative type inventory:

  1. What is the smallest creation result that returns exact installed capability and complete rejection ownership without structural paths?
  2. Can explicit typed worker readiness be expressed as ordinary protocol composition while proving the exact producer authority, incarnation and attempt correlation, asynchronous initiation effect, in-flight ownership, and accepted/rejected/cancelled/late settlement needed to avoid a universal activation subsystem?
  3. How does assignment.complete(result) produce a statically typed private parent report without exposing a parent path, customer route, helper trait, or generated alias?
  4. Can each actor expose one named semantic action product while keeping its interpreter requirements inferred and closed?
  5. Which public protocols genuinely need distinct acceptance, lifecycle, diagnostic, and terminal destinations?
  6. Which recovery values have exactly the same law in fixed supervision and the two pools after all three folds exist?
  7. Can shutdown be complete with the initial wait-for-owned-actors policy before deadline retirement is introduced as an independent extension?
  8. Can ordinary construction infer the finished behavior type without a public marker for every missing choice?

A negative answer is useful evidence. It authorizes only the smallest semantic surface named by that failed witness, not a general wrapper or utility family.

Ready for comparison and policy enrichment

The non-production experiment is ready to compare with the governing solution and enrich with omitted policy only when:

  • all five prototype folds implement the real Behavior/Actions boundary and pass pure state-machine tests against independent models;
  • each has accepted and rejected end-to-end interpreter traces;
  • invalid protocol/capability exchanges fail at compile time;
  • no ordinary example names a nonce, occurrence, path, generated effect product, typestate proof marker, or parent-report carrier;
  • no valid example supplies a no-op policy or placeholder type;
  • shared abstractions delete more prototype machinery than they add; and
  • the legacy implementation has not been imported, wrapped, or retained by a compatibility layer.

This gate authorizes comparison and policy enrichment only. Safe migration additionally requires:

  • applicable feature-catalogue parity recorded in the solution matrix;
  • the complete selected initialization-settlement and activation path;
  • accepted/rejected delivery settlement with surviving ownership;
  • wrapper-composition and initialization-order proofs in applicable orders;
  • complete orderly/forced shutdown and residual ownership handling;
  • compiler-pass/fail and ordinary DevX acceptance; and
  • every production prerequisite in the solution marked implemented and verified through its required interpreter and test layers.

Only after those requirements compose and the governing documents are updated together may the repository produce a migration/deletion proposal.

Disposition of the existing atomic documents

  • atomic-actor-features.md remains the exhaustive edge-case quarry. A row is promoted only when its policy enters an explicit implementation stage.
  • atomic-actor-solution.md remains the production design authority. Its open foundational mechanisms and dependency order remain production blockers; this experiment may test or falsify them but cannot bypass them.
  • atomic-actor-type-inventory.md is a list of hypotheses. No candidate name is authorized until the clean-room compiler and fold witnesses need its law.
  • atomic-actor-devx.md remains the eventual usability acceptance target, not the first source of builder types.
  • atomic-actor-retained-core.md governs the retained production-core audit. The temporary crate uses the real locked behavior boundary while testing whether template-level candidate machinery is necessary.
  • atomic-actor-research-audit.md remains the dead-end and discovery record.
  • atomic-actor-other-templates.md remains out of scope; the clean-room work does not trigger a catalogue-wide cleanup.

This keeps the detailed learning without making its accumulated candidate machinery the architecture of the replacement.

Atomic actor architecture map (engineering record)

Status: feature-complete normalization map. This document owns dependency direction and responsibility placement only. It does not restate aggregate state machines, runtime settlement, public construction syntax, or verification matrices.

Protocol vocabulary and reuse

Atomic protocols use names that expose timing and ownership. An input enters a behavior transition. A command carries application intent. A runtime request remains owned until interpretation returns either an exact receipt or a rejection containing the complete request and reason. An outcome or report is a later domain or lifecycle result, not proof of send acceptance. A reply is an application-level answer to a command.

When several operations have the same complete ownership and timing equation, that equation is represented once and parameterized by its domain request, receipt, rejection, or outcome values. Result<Receipt, (Request, Rejection)> is preferred for the exact two-alternative case. A separate sum is justified only by different alternatives, ordering, correlation, or retirement—not by a different aggregate name or message suffix.

Semantic authority map

ConcernOne normative owner
Stable-proxy transition lawactor-laws/proxy.md
Fixed-supervisor transition lawactor-laws/fixed-supervisor.md
Dynamic-supervisor transition lawactor-laws/dynamic-supervisor.md
FIFO-pool transition lawactor-laws/fifo-pool.md
Keyed-pool transition lawactor-laws/keyed-pool.md
Generic interpretation, settlement, and terminal custodyatomic-runtime-settlement.md
Application construction and usageatomic-actor-devx.md
Verification and evidence gatesatomic-actor-verification.md

The family documents in this directory own collaboration boundaries, policy classification, and realization gates. They link to the authoritative law matrices instead of copying them.

Worker means the concrete application-defined W: Behavior, not a Bombay trait or wrapper. Atomic templates may privately host that value through fresh creation, initialization, activation, exact capability ownership, and stop. WorkerSubmission<W, P> is the affine construction product pairing the worker with its activation work; it is not another actor abstraction. Stable service identity and replacement belong to StableProxy; roster and recovery policy belong to supervisors; assignments belong to pools; bindings belong to KeyedPool. Shared worker-hosting data may encode only equations that are identical in every real consumer and may never select those contextual policies.

InitialWorkerRejection is the one shared construction result used by Fixed, FIFO, and Keyed construction. It owns the callable, prepared prefix, unavailable role and reason, and untouched suffix. Each aggregate construction error embeds that value beside only its own policies. The private preparation operation runs before a behavior exists; it cannot run application code during a transition.

The StableProxy source location does not make intrinsic worker values proxy-owned. ActivationPlan, WorkerSubmission, opaque worker/ initialization/activation correlations, initialization and activation requests and results, exact established-worker custody, and pre-commit worker rejection are aggregate-neutral data. FIFO and KeyedPool now share only their proven direct-worker relationship beneath the private atomic::pool::worker hierarchy, while retaining the canonical atomic::* application/interpreter spelling. PendingWorker, WorkerStartResult, and ProxyDrain remain StableProxy concerns in their present form; a pool must not translate or ignore their proxy outcomes.

Dependency direction

Behavior interpretation law
    -> validated values and boundary records
    -> StableProxy
        -> FixedSupervisor
        -> DynamicSupervisor
    -> direct-pool semantic values
        -> FifoPool
        -> KeyedPool
    -> inferred construction and concrete protocols

Bombay Engine
    -> Behavior + Behavior Actors
    -> Address + Communication + Observe + Timers

The arrows denote use, never ownership reversal. There are no aggregate cycles. FixedSupervisor and DynamicSupervisor are independent folds that collaborate with the one StableProxy law. FifoPool and KeyedPool are independent direct worker folds; neither contains a proxy or supervisor and neither implements the other.

Repository responsibility

  • crates/behavior owns the pure Behavior fold, Actions, and only generic statically typed interpretation products proven useful across the catalogue.
  • crates/actors owns the five reusable aggregate laws and their concrete protocols, policies, builders, and pure folds.
  • Bombay owns the single Engine Driver, tasks, mailboxes, actor installation, activation, capability interpretation, observation, timers, and retirement.
  • Communication owns mailboxes; Address owns identity and leases; Observe owns completion publication; Timers owns scheduling state.
  • crates/behavior-testkit and the nested atomic experiment own independent models and falsification evidence, never production semantics.

Module ownership

Aggregate directories expose the ownership hierarchy directly. A child file uses the shortest name that is meaningful beneath its parent, and the aggregate mod.rs alone selects the public surface. For example:

stable_proxy/
    mod.rs
    state.rs
    protocol.rs
    effects.rs
    operation.rs
    worker/
        mod.rs
        initialization.rs
        activation.rs

Thus stable_proxy/worker/mod.rs reads as the proxy's exact worker ownership, without a redundant proxy_worker_start.rs filename. Nested modules do not widen visibility or create another transition owner; their parents control what may be used by sibling concerns and what reaches applications.

The fixed supervisor follows the same rule without decorative directories:

fixed_supervisor/
    mod.rs
    member.rs
    role.rs
    proxy/
        mod.rs
        start.rs
        stop.rs
        outcome.rs
    recovery/
        mod.rs
        correlation.rs
        preparation.rs
        stop.rs
    restart/
        mod.rs
        admission.rs
    shutdown/
        mod.rs
        member.rs

Each group uses its existing principal concern as mod.rs; there is no empty module whose only job is to make the tree deeper.

FIFO uses the same ownership rule with fewer concerns:

fifo_pool/
    mod.rs
    member.rs
    job.rs
    policy.rs
    protocol.rs
    requests.rs

mod.rs is the only transition authority. member.rs stores the current direct-worker relationship, job.rs owns customer custody and assignment reunion, and the other three modules separate validated application policy, application protocol, and interpreter requests. None receives arbitrary pool inputs or emits Actions independently. Creation, activation, readiness, assignment, recovery, and retirement are member alternatives, not one child module per arrival path.

Forbidden edges include Behavior depending on Behavior Actors, pools depending on StableProxy, supervisors depending on pool-private models, any Behavior fold depending on runtime services, or any component introducing a second Driver, mailbox, registry, lifecycle service, erased envelope, or dynamic capability map.

Law classification

Fresh allocation, isolated processing of one communication, sending to known recipients, and explicit next behavior are actor-model laws. Stable identity, supervision strategy, admission, affinity, retry, settlement products, and terminal customer outcomes are derived constructions. Creation-before-dependent operations, initialization settlement before ordinary ingress, diagnostic disposition, drain policy, and root terminal custody are deliberate Bombay policies. Family documents label policy choices without presenting them as Agha guarantees.

Campaign boundary

Entity/Mnesis persistence, ActorInterface, external actors, receptionists, HTTP, discovery, clustering, and process-exit policy are downstream constraints, not part of the five-fold implementation. Their migration requirements are recorded separately and cannot justify a compatibility alias in this campaign.

The normalized catalogue, canonical syntax prototype, exact dependency contracts, and total-settlement representation gates pass. Bombay owns the documented four-link terminal-custody change externally. Local production begins after the independent evidence commit and explicit clean-room deletion commit.

Developer-experience acceptance contract (engineering record)

Normative ownership: this is the single owner of canonical application construction and usage syntax for all five families. Aggregate law documents own transitions; atomic-runtime-settlement.md owns interpretation/custody; atomic-actor-verification.md owns evidence gates. Other documents link here rather than repeating builder orders or worker authoring syntax.

This document specifies what ordinary source must express for the five atomic actors. All five component construction syntaxes are selected and implemented. Bombay's role-first application assembly and runtime custody changes remain upstream work; component construction does not claim that integration complete.

The earlier code snippets are withdrawn. They looked copy-pasteable while leaving hosting, activation, effect lowering, replies, rejected delivery, and shutdown undefined. They also exposed or assumed manual Protocol implementations, runtime addresses, turbofish, handwritten behavior dispatch, pseudo-send, and unproven initialization syntax. None is an accepted API.

Application-defined workers

The application defines the actual worker as an ordinary concrete Behavior. It may be one domain behavior or an application-defined closed sum of domain behaviors. No Worker trait, runtime context, wrapper base class, callback, or atomic worker behavior is required. A template receives that behavior through a typed WorkerSubmission and owns only its relationship to the actor. In a pool, the worker receives Assignment<Job> and returns its result with assignment.complete(result); it does not know the pool, customer, completion route, structural parent path, or assignment identity.

Canonical public path

The Behavior Actors component has one external spelling for this family: behavior_actors::atomic::Name. Atomic names are not repeated at the component crate root. This module path communicates ownership; it is not structural actor routing.

Bombay must not glob-re-export behavior_actors::atomic. Its ordinary facade selects only these categories from the implemented families:

  • construction and behavior: StableProxy, fixed, FixedSupervisor, dynamic, DynamicSupervisor, fifo, FifoPool, keyed, and KeyedPool;
  • worker definition and activation: ActivationPlan, ImmediateActivation, WorkerSubmission, ActivationPolicy, EntryCapacity, BacklogCapacity, BindingCapacity, and ZeroCapacity;
  • required policy: ActorDrainPolicy, DiagnosticDisposition, Recovery, Strategy, RestartLimit, RestartRelease, FailureReaction, UnexpectedExit, PoolRecovery, PoolFailureReaction, and Interruption;
  • application protocols: FixedCommand, DynamicCommand, their reply values, query/status values, cancellation authority and outcomes, lifecycle values, diagnostics, FIFO/keyed customer outcomes, binding commands and replies, and typed policy errors; and
  • validated fixed topology: OrderedRoles, DuplicateRole, and the complete construction rejection.

Bombay's interpreter implementation imports doc-hidden request products, effect products, internal events, worker preparation, activation requests, proxy control, and settlements directly from the component module when their associated types require it. Bombay does not re-export those names. Therefore ordinary application autocomplete and rustdoc contain domain construction, policies, commands, capabilities, and outcomes rather than runtime plumbing.

Status and acceptance gate

The five component construction paths are feature-complete: each is implemented, inferred from domain values, and covered by a compile-pass contract. Bombay's role-first assembly and complete runtime journey remain active. That upstream journey requires focused proof of all the following together:

  1. imports and an ordinary concrete worker definition;
  2. construction with an inferred final behavior type;
  3. hosting through the current concrete interpreter boundary;
  4. initialization before activation;
  5. immediate and asynchronous readiness;
  6. command/job submission with concrete typed recipients;
  7. request replies, durable lifecycle events, customer outcomes, and the selected diagnostic disposition;
  8. rejected-delivery settlement after the source actor has stopped;
  9. orderly and forced shutdown; and
  10. pure-fold testing of the complete named Actions product.

The same prototype must include compile failures for each missing semantic choice and each invalid capability exchange. A snippet containing ignore, pseudocode, an undisclosed helper, or a support alias supplied only to appease inference is not evidence.

What users choose

Users choose only domain and policy values:

  • semantic roles and dynamic keys;
  • concrete worker definitions, jobs, and results;
  • a fixed topology or dynamic entry capacity;
  • immediate activation or a concrete statically dispatched activation plan;
  • a positive maximum number of unresolved activation authorizations;
  • recovery, strategy, budget, release, interruption, and ActorDrainPolicy values where those policies are meaningful;
  • concrete request, lifecycle, customer, and diagnostic routes; and
  • FIFO distribution, or keyed distribution with one key-to-role selector.

Users do not choose or construct child nonces, actor addresses, installation attempts, generations, activation attempts, timer identities, job identities, assignment identities, completion tokens, structural parent paths, effect lane positions, or settlement owners.

Construction laws

  • A constructor or complete builder produces one concrete actor; users do not name its full generic return type.
  • When a family has optional construction transformations, incomplete builders do not implement Behavior and have no build method.
  • One documented order exists for each actor. Repeatable topology entries are the only deliberately repeatable step.
  • A builder exposes no choice that its actor does not use. Dynamic supervision has no fixed factory or recovery placeholder; FIFO has no selector; pools have no proxy choice.
  • Missing required choices are typestate, not runtime flags.
  • Duplicate roles and other value-dependent failures are typed build errors.
  • No valid construction supplies a no-op callback, dummy recipient, empty factory, marker route, reply alias, output alias, or explicit generic merely to satisfy implementation plumbing.
  • Every route preserves its concrete logical, established, exact, or mixed delivery kind.

Diagnostic construction has exactly two semantic choices:

DeliverTo(concrete route)
Terminate

Terminate is the autonomous case. There is no mandatory .diagnostics_to(...), optional route plus hidden default, or recursive diagnostic fallback. A literal Diagnostics<Route>::Terminate is also rejected because it leaves an unused route type to infer. The selected builder must offer one route-bearing choice and one route-free choice without asking the user to name their typestate result.

Shared activation journey

Each fixed/dynamic supervisor and pool builder selects activation mode and a positive limit on unresolved activation authorizations. A proxy has the structural limit of its single pending worker. “Activation authorization” has one user-facing meaning: an owner has decided that a worker may progress toward Ready. A supervisor reserves conservatively when it emits the opaque proxy install because it sees no later progress facts; a direct pool reserves when it emits BeginActivation after initialization settlement. The difference is a documented template boundary, not two counting laws. The resulting journey is:

build definition
  -> supervisor records activation authorization before proxy install
     (a direct pool waits until initialization settles)
  -> run the pure initialization fold
  -> establish the host and commit installed-but-not-ready
  -> interpret and settle initialization Actions
  -> direct pool records activation authorization
  -> activation consumes the installation permit and plan
  -> exact Ready or ActivationRejected fact
  -> only Ready publishes or accepts work

The ordinary worker author supplies a concrete activation value; they do not send BeginActivation, mint an attempt, or route ActivationResolved. Immediate activation uses a route/plan-free builder choice; it must not require an annotation for an otherwise unused plan type. Initialization failure, rejected initialization effects, and stopping during initialization are observable pre-readiness outcomes; activation is never used to hide or rerun them. Cancellation recovers a worker definition only before the install/create action that transfers it. Cancellation after that ownership boundary is reported as pending—even if activation has not begun—and never claims that external hydration stopped. Late readiness is drained and never published.

Stable proxy journey

Most users never construct a proxy. Fixed and dynamic supervisors create and control one per stable service identity.

A direct proxy owner must be able to:

  1. construct an empty proxy without repeating the worker type;
  2. retain a private exact control capability;
  3. install the initial worker or request replacement by moving a definition;
  4. give clients only the stable service capability;
  5. exhaustively receive readiness, replacement, stop, unavailability, and contradiction reports; and
  6. shut down while creation or activation is unresolved.

Application clients cannot address install, replacement, readiness, or shutdown control. No public method sets a nonce, incarnation, or ready flag.

Fixed-supervisor journey

The selected semantic order is:

fixed(
    factory,
    ordered non-empty roles,
    activation policy,
    recovery policy,
    topology-failure reaction,
    ActorDrainPolicy,
    diagnostic disposition,
)
  -> optional lifecycle publication
  -> build and prepare every initial worker

The construction-only worker factory returns one WorkerSubmission: the worker definition and the concrete activation work for that exact attempt. Immediate workers use the inferred immediate construction; activated workers provide one owned plan per factory result. A multi-role actor never clones or rediscovers one plan stored beside the roster.

The successful supervisor does not store this callable or carry its type. Automatic recovery obtains submissions through a typed batch worker source in Actions. H38 selects the Bombay-interpreted typed worker-source action. An ordinary factory actor remains valid application architecture, but is not mandatory because accepted delivery still needs a later reply join. Canonical recovery-source syntax therefore names the application worker source and its typed rejection only. Bombay will implement the generic static interpreter and retirement transfer; no runtime path, source-result route, callback, or composed Behavior type appears in application code.

H52 proves the candidate diagnostic protocol for operating preparation failure. The diagnostic actor names FixedDiagnostic<Role, Worker, Plan, Source> directly as its domain message; no application alias is required. Source is the already-selected recovery capability type and statically selects its worker and source rejection types; the source value itself is never placed in a diagnostic. Applications inspect one owned WorkerPreparationFailure through role(), prepared(), remaining_roles(), and one exhaustive borrowed WorkerPreparationFailureReason. They never name immutable role storage, preparation tickets, action settlements, request lanes, or parent paths. This shape is implemented by the current fixed supervisor.

H53 lowers this protocol surface into the actors crate. Construction of the payload from an operating recovery remains the next independent transition stage; the public syntax no longer depends on that implementation detail.

The source implements method-free WorkerSource<Role, Worker, Plan> by naming only its worker-level and whole-source rejection types. Applications never construct PrepareWorkers, inspect WorkerPreparation, or name their generic types. Those interpreter-facing products remain hidden behind the supervisor's own recovery transition and the generic action-settlement path.

Recovery owns the complete automatic-recovery choice. Canonical construction is Recovery::permanent(source, strategy, limit, release), Recovery::transient(source, strategy, limit, release), or Recovery::temporary(). Permanent and transient recovery retain the concrete worker source that Bombay will invoke outside Behavior. Temporary recovery carries neither a source nor ignored strategy, budget, or release values. The activation policy owns only its positive authorization maximum; callers use ActivationPolicy::new(usize) and receive ZeroCapacity instead of constructing NonZeroUsize. The plan belongs to each worker submission. Passing all required values to fixed avoids a user-visible chain of structural builder stages; omitting any value is an ordinary missing-argument compile error.

The seven direct arguments were compared with a named policy product and another typestate builder stage. The product would merely regroup unrelated choices and the builder would expose more construction machinery without preventing another invalid exchange. The direct form remains canonical because the factory, roles, activation, recovery, topology reaction, drain policy, and diagnostics all have distinct semantic types. Lifecycle publication remains the one truthful builder transformation because it changes the resulting action protocol.

Roles are application domain values such as SearchRole::Index, not static strings, child positions, or runtime addresses. The factory receives a borrowed role and returns that role's concrete worker or a typed rejection. build prepares roles in declaration order. FixedConstructionRejected.workers is one InitialWorkerRejection containing the factory, every prepared member, the unavailable role and reason, and all untouched roles; the outer value contains only fixed policy. No partial supervisor exists.

The external lifecycle route is genuinely optional. Omitting it creates an autonomous supervisor; it does not create a discard sink. Operational failures still follow the selected diagnostic disposition. Route-free diagnostic termination is inferred directly; it requires neither a dummy route nor a route-type annotation.

All workers in one fixed supervisor expose one common public service protocol. Different behavior implementations may be variants of a closed concrete sum, but ordinary users should not need to hand-write forwarding solely because the supervisor API failed to compose existing behavior forms. Capability-safe heterogeneous public protocols remain a separate, unselected feature.

The lifecycle consumer, when configured, receives one flat semantic event sum containing exact ready proxy capabilities and complete failure facts. It never walks .inner, .own, WithParent, a slot number, or wrapper depth.

Dynamic-supervisor journey

The canonical constructor is one dynamic(entries, activation, unexpected_exit, actor_drain, lifecycle, diagnostics) call. Applications construct entries with EntryCapacity::new(usize) and activation with ActivationPolicy::new(usize). Both return ZeroCapacity, but their values cannot be exchanged. Every executable semantic policy appears once; there is no staged builder, factory, callback, default, marker, or public proxy type. ActorDrainPolicy is mandatory because global shutdown is executable.

A named policy product or another builder would only move these six unrelated choices behind an extra public name, so the direct form remains canonical. Bombay constructs the lifecycle and diagnostic peers first, passes their typed capabilities to this call, and then activates the returned supervisor; applications never name the final behavior type. H148 historically derived the role-first inference shape with stable Rust. The real role_first_construction_returns_the_complete_behavior integration test now owns that syntax; H589 removes the superseded private facsimile. The earlier H135/H137 fragments remain rejected because they fabricated capabilities before the code under test.

Bombay must declare and establish application actors by semantic role before it constructs the root. Its one-time application assembly supplies typed logical or exact capabilities for those actors to the root constructor. The lifecycle actor's concrete protocol then supplies the dynamic supervisor's key, worker, and activation types; the diagnostic actor supplies its own concrete protocol. The resulting root capability makes every command, including Stop { key }, infer without an alias, annotation, turbofish, raw runtime address, structural path, dummy route, or fixture capability. Bombay performs this assembly outside Behavior; the constructor performs no I/O and is never stored in the supervisor.

Bombay's assembly method names remain an upstream choice, but the required source shape is role-first topology, typed peer capabilities, one pure root construction, then ordinary delivery through the returned root handle. A root-first API that asks the user to repair missing types is not compatible. H148's frozen proof compiled all five commands through the returned typed capability. Current dynamic integration tests exercise all five real commands, and the real construction test retains the inferred behavior syntax. Removing worker and activation provenance from the lifecycle capability failed at construction; detaching Stop from that capability failed with E0282.

The durable lifecycle route is mandatory and configured once. A start, replace, stop, query, or cancel request carries only its temporary reply route. No request may become, replace, or transfer the durable owner. Stop is the single public operation that drains and removes a ready or empty entry; there is no second retirement command.

Start and replace replies distinguish admission from realization. Admission returns an opaque CancelAuthority. Later readiness or failure goes only to the configured durable lifecycle route. Cancellation has the complete phase-sensitive outcomes selected by AA-20; only cancellation before definition transfer returns the definition.

Start and replace share one direct result equation because their accepted ownership is identical: WorkerChangeReceipt or WorkerChangeRejection with an operation-specific reason. Stop uses its own direct Result. Cancellation returns CancellationReceipt::{Returned, Pending, Committed, Cancelled, Stale, Draining}; query returns its independent known/unknown reply. There is no catch-all DynamicReply and no alias that merely renames Result.

Start preparation is transaction-local: successful admission commits the creating-proxy entry and emits proxy creation in the same transition. Query therefore exposes creating proxy, waiting for activation authorization, awaiting proxy outcome, ready, empty, stopping, replacing, cancelling, draining, or retiring—never a stored Reserved phase. It does not invent worker progress absent from the proxy report protocol. An unknown key is a distinct outcome.

FIFO-pool journey

The selected construction spelling is one direct call:

fifo(
    initial_factory,
    ordered unique roles,
    ActivationPolicy,
    PoolRecovery,
    BacklogCapacity,
    Interruption,
    ActorDrainPolicy,
    DiagnosticDisposition,
)

Every argument has a distinct domain type, so exchanging backlog and interruption is a compile error. BacklogCapacity::new(0) is valid because zero means no waiting work. A named policy product owns no new invariant; a fluent form adds missing-state machinery. Neither is retained.

The call prepares the complete roster before a pool exists. Success returns a FifoPool whose type does not contain the callable. Failure returns FifoConstructionRejected: its workers field is the shared InitialWorkerRejection, beside only FIFO policy. Automatic PoolRecovery owns its source, limit, release, and RetireRole | StopPool reaction. Temporary recovery owns only the reaction and needs no source placeholder. No transition invokes the factory, and users never name preparation or interpreter machinery.

Submission moves a caller request correlation, payload, and concrete customer route to the pool. Accepted and Rejected both echo the request correlation; the pool never trusts it as its internal job identity. Admission either returns the payload in Rejected or creates one authoritative customer obligation identified by a fresh opaque job value and immutable admission ordinal. Terminal customer outcomes are exactly:

Completed { job, role, result }
ReturnedQueued { job, payload, reason }
ReturnedAssigned { job, role, payload, reason }

The pool, not the worker, retains and selects the customer destination. Retry is explicitly at-least-once execution: the pool keeps the authoritative obligation and retained retry payload while a cloned execution payload is at the worker. An interrupted retry is reinserted by its immutable admission ordinal. This preserves admission order even when several active workers stop in a different order; unconditional front insertion would reverse those jobs.

Pool-worker authoring

The intended worker expression is now a production compile contract in crates/actors/tests/fifo_pool/compile.rs:

#![allow(unused)]
fn main() {
fn transition(&mut self, assignment: Assignment<Job>) -> WorkerActed<Self> {
    let result = self.process(assignment.payload());
    Ok(Actions::cont().with_send(assignment.complete(result)))
}
}

The behavior_actors::atomic::pool_worker attribute is syntax derivation only. It reads the authored Assignment<Job> input and declared result type, rewrites the intentionally unresolved WorkerActed<Self> spelling, and emits the sole ordinary Protocol, Behavior, and BehaviorBase implementations. There is no public WorkerActed type, worker trait, adapter actor, callback, result marker, or alternate transition. The worker body names no parent path, lane, assignment identity, completion route, composed behavior type, or alias.

Exact source inspection and the compile experiment distinguish the mechanisms:

MechanismResult
inherent Assignment::completecleanly constructs and consumes the affine completion value, but cannot select the worker's already-declared Behavior::Sends
extension trait or associated typehas the same associated-send boundary; a worker-specific associated trait would become a forbidden second actor trait
generic closure/buildercan infer a wrapper's output type, but changes the owning authoring form and does not make the shown inherent method a Behavior fold
typestateproves builder completeness but does not solve send-product selection
stable return-position impl Traitcannot supply the named Behavior::Sends associated type on stable Rust 1.95
syntax-only macro derivationeligible: it can preserve the authored method, rewrite WorkerActed<Self> during expansion, and emit the one concrete Behavior implementation with its completion send type

The earlier private declarative stand-in remains historical evidence for two unrelated workers and exact typed interpretation. Production now proves the same generated completion capability through the actual ReceiveTimeout<Deadline<Worker>> and Deadline<ReceiveTimeout<Worker>> orders. Both composed send products satisfy total settlement and the one sealed pool-completion capability without an adapter or placeholder reaction.

The production surface exposes only Assignment<Job> and opaque Completion<Result> values. Rustdoc proves that external code cannot mint a pool-issued job identifier, construct an assignment, forge a completion, or complete the same assignment twice. It also rejects missing macro declarations and a transition that receives an unrelated input. All 38 Actors rustdoc contracts pass on stable Rust 1.95. Deliberately deriving the completion lane from Job instead of the declared result fails at the authored assignment.complete(result) expression with the exact SearchJob versus SearchResult mismatch.

The complete canonical FIFO journey occupies 38 meaningful lines including imports, domain types, worker, worker declaration, construction, and initialization. The worker implementation occupies six meaningful lines and the direct fifo(...) call ten. It needs no final aggregate annotation, helper alias, turbofish, structural actor concept, interpreter request, or completion route. The direct eight-domain-value constructor remains the single selected construction spelling.

Keyed-pool journey

The selected construction spelling is one direct call:

keyed(
    initial_factory,
    ordered unique roles,
    key-to-role selector,
    ActivationPolicy,
    PoolRecovery,
    per-role BacklogCapacity,
    BindingCapacity,
    Interruption,
    ActorDrainPolicy,
    DiagnosticDisposition,
)

The callable factory exists only during construction; the successful KeyedPool does not store it. KeyedConstructionRejected.workers is the shared InitialWorkerRejection, beside the selector and keyed policy. The selector is the one concrete Fn(&Key) -> Role value used by future admission; it is not a boxed callback, runtime registry, or distribution mode. ActivationPolicy, BacklogCapacity, and BindingCapacity are distinct types, so their numeric storage cannot make them interchangeable.

Keyed admission has one selected model:

Submit { key, payload, reply_to }
selector: concrete Fn(&Key) -> Role

There is no KeyedJob and no SelectWorker trait. The submitted key is explicit; one statically stored concrete function or closure maps that key to a role. FIFO accepts no selector.

The selected semantic order reuses FIFO's accepted-job and direct-worker value laws but substitutes per-role backlog and keyed distribution for global FIFO backlog and circular worker selection. Rebalance and unbind use typed management replies, carry Absent | Exact(binding_generation) expectation, and affect future admission only. Role-changing rebalance issues a fresh generation; same-role rebalance is an accepted no-op preserving it. An absent key may be bound either with accepted admission or by explicit rebalance. Absence stores no Unbound entry, and accepted jobs retain only opaque { generation, role } evidence rather than a cloned key.

Committing permanent role unavailability automatically unbinds every retained binding for that role, releases binding capacity, and emits exact key/generation diagnostics. Temporary recovery retains bindings. An idle ready target assigns immediately. Prepared, creating, initializing, waiting-for-authorization, activation-dispatched, activating, busy, recovering, or pre-ready-draining-with-retained-recovery targets may admit only to their own backlog when capacity remains. Stopping, retired, terminally draining, and shutdown-owned targets reject without retaining either a new binding or the submitted job; zero backlog therefore accepts a fresh key only when its selected target is ready-idle.

Rebalance uses a separate exhaustive target projection because it carries no job: every admission-backlog phase above, including temporary recovery, is bindable without consulting queue capacity, while stopping, retired, terminally draining, shutdown-owned, and unknown targets reject the complete command. Stale absence or generation expectation is rejected before target validation and cannot mutate a later binding.

Bombay hosting and sending

The component construction and command spellings are selected. Bombay's application-level hosting spelling remains upstream work. Its accepted example must reuse the concrete interpreter contracts after the documented Bombay changes; it may not invent RuntimeAddr::application(), a global envelope, implicit ambient runtime, or a template-specific host. Likewise, application communication must use the existing typed delivery values rather than a pseudocode send.

This is a usability requirement, not permission to widen core constructors or add convenience traits. If the current boundary cannot express the journey, the prototype must identify the precise missing semantic law before any new production symbol is proposed.

A forced actor-graph summary is not the final application return while an external activation or late exact drain remains unresolved. The root run future continues to own and process that residual settlement and resolves only after it is empty. Ordinary source must not receive a cloneable residual report and accidentally treat it as completed shutdown.

ActorDrainPolicy has exactly WaitForActorGraph and RetireActorGraphAfter { deadline }. The latter retires the represented actor graph after the deadline; it does not promise bounded process exit. No separate process-exit policy is selected in this design.

Pure-fold testing

Each template must expose its ordinary Behavior initialization and event fold to tests. A test supplies concrete typed facts, consumes one state plus one event, and asserts the complete named Actions product and next verdict. It does not spawn tasks, sleep, consult a clock, predict nonces, discard actions, or use a test-only dynamic envelope.

Activation, monotonic time, delivery rejection, late settlement, child stop, completion, and shutdown are typed inputs. Interpreter witnesses separately prove that those facts can be produced and that settlement survives the source actor.

Required compiler diagnostics

Focused compile-fail fixtures must reject:

  • build before every mandatory semantic choice;
  • fixed or pool topology with no role;
  • zero activation-authorization limit;
  • a worker with the wrong service or assignment protocol;
  • completion with the wrong result or without the issued assignment;
  • worker selection or substitution of the customer destination;
  • a FIFO selector, or keyed construction without its one selector;
  • cross-domain key, worker, reply, lifecycle, or operation capabilities when their semantic Rust types differ;
  • use of an established proxy capability as another protocol; and
  • application construction of attempts, generations, job IDs, completion tokens, parent paths, or settlement owners; and
  • ordinary application errors that expose a topology-derived settlement product, occurrence path, or type whose diagnostic grows with wrapper depth;
  • a terminal lift that omits a heterogeneous child variant or exact source provenance; and
  • treating an actor-side forced summary as the final root-run result while residual activation ownership remains.

Diagnostics are measured at the missing or invalid semantic choice. An error whose useful cause is hidden inside nested associated types, positional effect paths, or a repeated turbofish fails the DevX gate even if the invalid program eventually fails to compile.

Runtime instances with the same public protocol are deliberately not assigned compiler-only owner brands. For DynamicSupervisor, an authority issued by another same-signature instance is accepted as typed input and returns CancellationReceipt::Stale by AA-20's exact operation correlation. Adding an owner marker solely to turn that runtime law into a compiler denial would add a generic parameter with no application substitution law.

Copy-paste deliverables

Before the API can be called selected, the repository needs five complete, warning-clean examples—proxy owner, fixed supervisor, dynamic supervisor, FIFO pool, and keyed pool—plus a sixth example showing pool assignment completion through two wrapper orders. Each must cover the entire acceptance gate at the top of this document. At present none exists; this is recorded as an implementation blocker, not concealed with aspirational snippets.

Exhaustive feature catalogue for atomic actor templates (engineering record)

This document records the observable requirements that the replacement actor templates must satisfy. It intentionally makes no decision about Rust types, builders, internal state layout, shared helpers, or implementation strategy. Those decisions belong in a later design document.

The catalogue was assembled from the existing supervisor, proxy, pool, interpreter, model, property, exhaustive, and fuzz contracts. Existing implementation names are not requirements unless the behavior itself appears below.

The atomic templates in scope are:

  1. stable worker proxy;
  2. fixed supervisor;
  3. dynamic supervisor;
  4. FIFO worker pool; and
  5. keyed worker pool.

Every feature group below has a stable identifier in brackets. Individual bullet requirements are referenced by one-based ordinal: the first bullet under [PX-REPLACE] is PX-REPLACE-01, the second is PX-REPLACE-02, and so on. Adding a requirement appends a new ordinal; existing IDs are not reused.

Requirements shared by every template

[SH-ACTOR] Actor boundary

  • The template is one concrete, statically dispatched Behavior fold.
  • One input is processed at a time.
  • A successful transition returns all communications, fresh creations, and the next behavior or termination decision through Actions.
  • Initialization is a pure fold whose actions are interpreted before mailbox inputs.
  • No template performs delivery, allocation, observation, scheduling, clock access, or shutdown directly.
  • No template depends on an executor, transport, global registry, runtime query, ambient context, or hidden side channel.
  • No template wraps an arbitrary application behavior merely to gain lifecycle machinery.

[SH-STATIC] Static protocol and capability safety

  • Public commands, private parent-to-child inputs, child-to-parent reports, runtime facts, effect lanes, errors, phases, reply recipients, child behavior alternatives, and creation products are statically known.
  • No trait object, Any, downcast, erased message, runtime protocol lookup, string key, serialization envelope, or unsafe type escape is permitted.
  • A semantic role or dynamic management key is never treated as an actor address, established capability, creator-local nonce, or proof of freshness.
  • A creator-local nonce is never treated as an actor identity or proof that a child was installed.
  • Every send to an exact installed actor uses an established capability or an exact creator-local child binding, as appropriate. A stable proxy never exports its worker recipient; owner-visible worker incarnation data is opaque non-routable evidence.
  • Heterogeneous workers are represented by one closed application-defined sum whose variants remain statically dispatched.

[SH-CREATE] Fresh creation and provenance

  • Every new actor incarnation is staged as a fresh creation.
  • A nonce collision, allocation exhaustion, address collision, initialization rejection, installation failure, or commit failure never overwrites an existing binding.
  • Initial birth and replacement incarnation remain distinct provenance.
  • Replacement provenance is attached when fresh creation commits, but a successful Restarted outcome is reported only after that exact replacement incarnation becomes ready.
  • A rejected replacement never emits a successful restart or birth outcome.
  • Same-action dependent observations or sends rely on the documented creation-before-send interpretation order and retain typed rejection.
  • Converted or generated nonce values cannot silently repeat a previously issued creator-local nonce.
  • Exhausted nonce, attempt, operation-ticket, timer identity, timer generation, assignment, and job sequences have typed outcomes; production panics are not accepted.

[SH-READY] Installation, activation, and readiness

  • Committed actor creation proves installation, not application readiness.
  • The runtime first runs the concrete behavior's pure init fold exactly once. If that fold rejects, no host is committed and none of its returned effects exists. Activation never calls init a second time.
  • After a successful init fold, the runtime establishes provisional/exact host ownership and commits an installed-but-not-ready incarnation before interpreting any initialization Actions.
  • Initialization actions may partially succeed. Their later rejection cannot reject or erase the already committed installation and cannot pretend an earlier delivery, creation, or state transition did not occur.
  • Host/allocation rejection before commit, initialization-fold rejection, initialization-effect rejection after commit, and initialization stop after commit are distinct typed pre-readiness outcomes. Post-commit rejection or stop drains the exact installed incarnation and issues no activation permit.
  • Every worker definition selects one concrete statically dispatched activation plan. An immediate plan performs no external work but still resolves readiness only after behavior initialization succeeds.
  • Committed installation yields an actor-retained exact installed-but-closed incarnation, initialization-settlement ownership, and the same concrete activation plan moved into creation. Only complete successful initialization settlement yields that plan plus the distinct one-shot activation permit tied to the incarnation; no plan is cloned or rediscovered.
  • The activation interpreter accepts a typed BeginActivation request owning an opaque attempt, the one-shot installation permit, and the concrete plan. The actor's activating state retains the exact incarnation and attempt correlation, not the moved permit or plan.
  • Start rejection returns the complete unaccepted request through the surviving action settlement; accepted activation eventually produces one exact ActivationResolved fact: ready or activation rejected.
  • Fixed and dynamic supervisors and both pools select a positive maximum number of unresolved activation authorizations. Authorization means the owner's decision to let one worker progress toward Ready; that is the one user-facing counting law. A supervisor deliberately reserves its ticket conservatively when it emits the opaque proxy install input, while a direct pool reserves when it emits BeginActivation after initialization settles. A proxy has a structural local limit of one. Reserved definitions beyond an owner's bound remain actor-owned and have not crossed that template's authorization boundary.
  • Readiness is correlated to the exact installed incarnation and activation generation; a role, key, nonce, or timestamp alone is insufficient.
  • A supervisor does not publish Started or Restarted, a proxy does not route a command, and a pool does not assign a job until the exact worker is ready.
  • Initialization actions and their settlement complete before an immediate-ready outcome or external activation request can make the worker routable. Failure prevents readiness but never reverses installation.
  • Ready, rejected, stopped, and shutdown facts that may race are joined once by the actor that owns their exact correlations.
  • Duplicate, stale, foreign, or contradictory activation facts preserve all authoritative inputs and cannot make an incarnation ready.
  • Asynchronous hydration, I/O, and wall-clock waiting remain outside the pure behavior fold; only their typed completion fact enters the fold.
  • Activation rejection is distinct from creation rejection and ordinary terminal outcome throughout recovery, diagnostics, and shutdown.
  • Cancellation returns a definition only before the exact install/create action that transfers it. The interval after that transfer but before BeginActivation is already logical cancellation and cannot claim to return the definition. After activation emission, cancellation additionally closes publication irrevocably but does not claim that external hydration was physically cancelled.
  • A ready fact arriving after logical cancellation is a typed ReadyAfterCancellation outcome. The incarnation is never advertised and is drained exactly once.
  • A rejection arriving after logical cancellation resolves the attempt without fabricating readiness and retains the exact rejection.
  • Forced shutdown may retire the actor-side attempt while external activation remains in flight. The activation settlement owner survives the actor and owns any later ready/rejected fact; a stopped actor is never its destination.

[SH-CORRELATE] Fact correlation and transition integrity

  • Every creation, stop, shutdown rejection, timer, completion, and child report is correlated to its exact pending operation and incarnation.
  • A stale, duplicate, foreign, malformed, wrong-provenance, or contradictory fact cannot advance, revive, overwrite, or partially mutate current state.
  • When rejection must return owned input or authoritative facts, the complete values are returned without reconstruction or cloning used to escape ownership.
  • Preparation and validation finish before the single state commit.
  • A failed multi-member decision performs no partial budget charge, member reservation, replacement send, assignment, dequeue, or binding change.
  • Effect products use semantic lane names and append every lane exactly once in lane order.
  • Adding an unrelated outer behavior composition cannot drop, duplicate, reorder, reinterpret, or require callers to recount a structural path for the template's events or effects.

[SH-DELIVERY] Delivery acceptance and rejection

  • Emitting one delivery in Actions means one delivery attempt, not proof that the destination received or processed the value.
  • Logical, established, child-local, and structural-parent routes remain distinct concrete route kinds; a template never upgrades or downgrades one implicitly.
  • Every named effect product projects one closed rejection sum with a variant per delivery lane. Each variant owns the complete payload, route kind, and capability-level reason.
  • Every emitted item has one ordered settlement: accepted, rejected, or not attempted because an exact declared prerequisite rejected. A settlement is a named per-lane product, so several failures in one action cannot collapse into one sum value or discard later payloads.
  • A rejected prerequisite suppresses only its dependent effects and returns them untouched with an opaque reference to the one authoritative prerequisite settlement. The rejection payload is not cloned into every dependent item. Independent later lanes are still interpreted in their documented order.
  • Interpreting an action establishes a typed settlement owner before the first delivery attempt. Settlement outlives the source turn and source actor.
  • Every lane declares a primary rejection consumer and the surviving settlement owner used if that consumer is stopped or unreachable.
  • A continuing actor may receive its typed rejection as a later runtime fact; the settlement owner retains fallback ownership until that fact is admitted.
  • The Driver gives the current action's transitive settlement chain priority on the typed system lane. It admits each fact to the live source or transfers it to the surviving host; the next ordinary user communication is admitted only if that chain quiesces or transfers outward. Thus unresolved batches do not accumulate across separate user turns.
  • Settlement discharge is local to that source/host chain and does not impose a global actor-system barrier. Actions emitted while processing a settlement fact are themselves settled before the next ordinary source communication.
  • This priority rule only prevents accumulation across separate ordinary user turns. A transitive settlement chain may be unbounded or non-terminating; the iterative Driver queue prevents stack growth but proves neither memory bounds, fairness, nor eventual return to ordinary traffic.
  • The application root remains the live owner of transferred settlement until every external activation, late lifecycle fact, and required exact drain has resolved. A final runner result is not produced while residual ownership exists.
  • A delivery emitted by a stopping actor, or rejected after the actor stops, goes directly to settlement. Returning it to the emitter is forbidden.
  • A delivery rejection cannot roll back the already committed source-actor transition or pretend that the corresponding state change never occurred.
  • Automatic retry is forbidden unless the template exposes and applies an explicit retry policy; otherwise rejection is a typed terminal or diagnostic outcome.
  • A closed exact endpoint, unavailable logical destination, rejected child input, rejected structural-parent report, and late reply are distinct where their recovery choices differ.
  • Long-lived customer and lifecycle destinations are retained by the actor that selected them. A worker receives no forgeable same-protocol capability whose substitution could redirect a pool or supervisor outcome.
  • Delivery-rejection tests exercise both the source fold and the interpreter return path; inspecting the emitted Actions value alone is insufficient.

[SH-DIAGNOSTIC] Diagnostic disposition

  • Every template that can produce an operational diagnostic has exactly one semantic disposition: DeliverTo(Route) | Terminate. This is a domain sum, not authorization for a Rust Diagnostics<Route>::Terminate value whose unused Route requires annotation. The builder must infer either a route-bearing concrete state or a route-free terminal state. An owner-created proxy is fixed to DeliverTo its exact structural parent and needs no second builder route.
  • DeliverTo attempts one delivery to the concrete logical, exact, or mixed route. It requires no second callback or fallback route.
  • Rejection of a diagnostic delivery produces one terminal UndeliverableDiagnostic settlement containing the diagnostic and route reason. It never emits another diagnostic delivery.
  • Terminate performs no diagnostic delivery. The fold emits the first diagnostic through a named terminal-settlement request in Actions and selects Step::Stop; the interpreter settles that explicit value with the surviving lifecycle host.
  • A root host retains terminal or residual settlement in the live application run future and returns a final value only after it is settled; a child host transfers through the child's typed lifecycle settlement. Neither path depends on the stopped actor's mailbox.
  • If an intermediate host also stops, the exact settlement transfers outward through its statically known host chain without reinterpretation. It cannot remain forever in an unreachable host.
  • Terminate stops in the diagnostic-producing turn after preserving its other actions. Rejected diagnostic delivery stops a still-live source when its settlement fact is admitted; if it cannot be admitted, the host/root terminal settlement is the final disposition.
  • Diagnostics are never silently logged, dropped, retried, or converted to a coarse Crash.
  • A template without an external diagnostic consumer uses Terminate; it never supplies a dummy recipient or no-op callback.

[SH-SHUTDOWN] Shutdown

  • Shutdown is a typed input accepted in every live phase.
  • The first shutdown request begins one terminal drain; later requests do not duplicate effects.
  • Every owned established child is asked to stop at most once.
  • Pending child creation is resolved before the owner decides whether a child must be stopped or is already absent.
  • Rejected pending creation counts as drained and creates no fabricated child.
  • A child installed while shutdown is pending is asked to stop exactly once.
  • An exact shutdown rejection retains its capability-level reason.
  • Delayed work or recovery retained at shutdown is cancelled without being emitted later; its exact timer fact can be consumed without reviving it.
  • Termination occurs only after every owned child is resolved and drained.
  • The final action retains all required reports and shutdown effects before selecting normal termination.
  • Every owner chooses one ActorDrainPolicy: WaitForActorGraph or RetireActorGraphAfter { deadline }. The former may wait indefinitely; the latter bounds actor-graph retirement only. Neither is a process-exit policy.
  • Deadline-retirement facts use interpreter-authored monotonic time and exact timer identity/generation. Rejection of deadline scheduling immediately forces the same typed host transfer with scheduling rejection as its cause; it never degrades RetireActorGraphAfter to unbounded waiting.
  • Deadline retirement preserves a typed forced-retirement fact containing the affected child, incarnation, phase, outstanding ownership, and cause.
  • Deadline retirement atomically transfers that outstanding ownership to the surviving lifecycle host. The actor-side member then counts as drained; exact late facts and rejected effects settle with the host and cannot revive the actor.
  • RetireActorGraphAfter bounds actor-graph drain, not an uncancellable external activation. The root run future remains pending in a typed residual-drain state until transferred work resolves; an actor-side forced summary is not the final application result.
  • Forced retirement never fabricates an accepted shutdown, normal child stop, successful activation, completed job, or completed restart.

1. Stable worker proxy

[PX-IDENTITY] Identity and ownership

  • One proxy provides one stable public worker-protocol identity.
  • At most one worker incarnation is current behind that proxy.
  • Every worker incarnation is a fresh child creation.
  • The proxy alone owns the mapping from its internal worker nonce to current incarnation state and the routable worker recipient. Parent outcomes expose only opaque non-routable incarnation evidence.
  • A replacement never replaces an actor at an existing address.

[PX-INIT] Initialization and installation

  • Initialization is explicit and cannot run twice.
  • The matching committed-creation fact proves only installed-but-not-ready; initialization effects still require exact settlement, and the initial worker remains unroutable until its later readiness outcome.
  • Initial creation is tagged as ordinary birth, never inferred replacement.
  • Worker creation is observed exactly once.
  • Worker termination is observed for the exact created incarnation.
  • A rejected initial creation leaves the proxy live but empty unless shutdown is already pending.
  • A worker stop that becomes observable before its creation-resolution fact is either joined correctly in either order or made impossible by the later architecture; it can never result in a dead worker becoming ready.
  • A rejected creation and an authoritative stop for the supposedly rejected incarnation form a typed contradiction retaining both facts.

[PX-ACTIVATE] Worker activation

  • Successful worker creation moves the proxy to an installed-and-initializing phase. Only complete initialization-action settlement yields the exact activation permit and moves it to activating; even immediate activation cannot bypass that phase.
  • A reported-ready fact makes only the exact installed incarnation routable.
  • Activation rejection drains the exact installed incarnation, then leaves the stable proxy live and empty and returns the exact rejection plus terminal or forced drain fact to its owner.
  • Rejection of the BeginActivation action preserves the complete unaccepted permit, plan, and request reason, drains the installed incarnation, and is a distinct proxy outcome from rejection by an accepted activation plan.
  • Initialization-fold rejection and host rejection leave the stable proxy live and empty without interpreting initialization effects. Post-commit initialization-effect rejection first drains the exact installed incarnation, then reports its rejection plus terminal-or-forced drain fact and leaves the proxy empty. All are distinct from activation rejection and none starts activation.
  • Worker stop before readiness reports one stopped-during-activation outcome; it is never reported as Started followed by an inferred stop.
  • Replacement is reported as completed only after the replacement incarnation is ready, not merely installed.
  • Shutdown during activation resolves the exact activation/stop join and does not publish a transient ready capability.
  • A command received while installed or activating is returned complete as unavailable.
  • “Atomic installation/activation outcome” means one proxy fold commits one state and one Actions value; it makes no cross-actor atomic-delivery claim.

[PX-ROUTE] Command routing and unavailability

  • In the ready phase, one admitted command produces one delivery to the exact current worker incarnation.
  • No command is delivered to a prior, pending, rejected, stopped, stopping, or shutdown worker incarnation.
  • In every non-ready live phase, the complete original sender and command are returned exactly once as expected unavailability.
  • Unavailability distinguishes at least initial installation, replacement, empty, stopping-for-replacement, and shutdown phases sufficiently for an owner to choose retry or rejection without guessing.
  • Creation rejection is expected unavailability, not an actor crash.

[PX-REPLACE] Replacement

  • A replacement request carries the complete new worker definition.
  • Only one replacement attempt is owned at a time.
  • An overlapping replacement is rejected with the submitted definition intact.
  • If a worker is running, replacement first requests shutdown of that exact incarnation.
  • If the proxy is empty after a known prior incarnation, replacement can stage a fresh successor immediately.
  • A replacement request reserves all locally fallible correlation state before asking the old worker to stop.
  • The fresh creation is explicitly tagged with the exact incarnation it replaces.
  • Worker-stop reporting and replacement creation effects are both preserved when emitted by the same transition.
  • A rejected replacement leaves the proxy empty and preserves the last successfully installed incarnation as provenance for a later attempt.
  • A successful replacement becomes routable only after its exact activation resolves ready; committed creation alone remains non-routable.
  • Stale creation and stop facts cannot affect a later attempt.

[PX-STOP] Worker termination

  • A spontaneous stop of the exact current worker is reported once and makes the proxy empty.
  • A stale or duplicate stop is rejected without state change.
  • A stop expected by replacement is reported once and cannot initiate a second replacement.
  • Worker stop and creation resolution are order-independent where the runtime can deliver them in either order.

[PX-SHUTDOWN] Proxy shutdown

  • Shutdown while ready asks the exact worker to stop and waits for its stop fact.
  • Shutdown while worker creation is pending waits for the creation result.
  • If that creation commits, the exact worker is stopped once; if rejected, the proxy terminates without a shutdown request.
  • Shutdown while replacement is stopping the old worker cancels the not-yet- created replacement and continues draining the old worker.
  • Shutdown while replacement creation is pending resolves that creation and drains any committed incarnation.
  • Shutdown after an already observed worker stop never sends to the dead incarnation.
  • A shutdown rejection is accepted only for the exact pending worker shutdown and preserves its typed reason.
  • The proxy terminates normally only after it owns no live or unresolved worker.
  • Rejection of a parent report during drain preserves the complete report and route rejection through the configured diagnostic/error path; it does not reopen the proxy or repeat worker shutdown.

2. Fixed supervisor

[FS-BUILD] Definition and construction

  • Construction requires a worker factory, at least one semantic child role, a complete recovery policy, and a topology-failure reaction.
  • An incomplete definition cannot implement Behavior or call build.
  • Duplicate semantic roles are rejected before initialization.
  • An empty fixed fleet cannot be built.
  • Initial factory rejection is typed and occurs before any initialization action is emitted.
  • One factory constructs both initial and replacement workers for each role.
  • A homogeneous fleet uses one worker behavior type.
  • A heterogeneous fleet may use one closed worker-behavior sum only when every variant implements the same public protocol. Different public protocols are separate typed supervisor instances unless a later law proves a capability-safe heterogeneous product; they are never collapsed to one weak common envelope.
  • Application actors and application births remain outside supervisor ownership; the supervisor never adopts unrelated child occurrences.
  • Lifecycle publication is an explicit route-selected capability, not a hard-coded logical recipient. Logical, established, and mixed routes retain their existing static hosting obligations.
  • A supervisor whose children are autonomous can be built without a lifecycle consumer and without supplying a no-op route; query and diagnostic laws must still remain truthful.
  • Construction selects an activation contract, activation-authorization limit, ActorDrainPolicy, and diagnostic disposition (DeliverTo or Terminate). These are semantic requirements, not optional callbacks; lifecycle-event publication remains the independent optional capability.
  • When lifecycle publication is selected, Started and Restarted carry the exact stable proxy capability needed to communicate with the ready role. They never carry a worker recipient; worker provenance remains private supervisor correlation evidence.

[FS-TOPOLOGY] Stable child topology

  • Exactly one stable proxy is staged for every declared role, in declaration order.
  • Every staged proxy has exact creation and termination observation.
  • A role is associated with its proxy through supervisor-owned state, never by converting the role into a nonce.
  • A role becomes available only after its proxy is committed, its install/replace input is accepted, and that exact proxy emits its single atomic Ready outcome.
  • After proxy commit, the supervisor may retain the worker definition in a WaitingForActivationAuthorization state. It does not send the install input until one global activation slot is reserved for that role.
  • The supervisor owns at most its configured positive number of unresolved proxy install/replace operations. Waiting roles are authorized in declaration order and retain their definitions without entering the proxy.
  • The exact established proxy capability is retained and can be reported to the supervisor's owner.
  • Stable-proxy creation rejection cannot fabricate a worker, replacement, or availability outcome.
  • Stable-proxy stop retires only the matching role unless the configured failure reaction stops the complete supervisor.
  • A stopped proxy is never sent another worker or shutdown command.
  • Facts for application children, foreign proxies, or stale proxy generations are returned or rejected complete without changing owned topology.

[FS-FACTS] Worker lifecycle facts

  • Worker readiness/stop reports are accepted only from the exact owned proxy and exact pending supervisor operation. Replacement outcomes additionally match their nested prior-incarnation evidence; no supervisor recovery ticket is injected into the proxy protocol. Worker creation, initialization, and activation progress remain proxy-private; the supervisor consumes only the proxy's atomic outcome.
  • Initial worker creation rejection is reported once and leaves no routable worker.
  • Replacement creation rejection is reported once and is not called a completed restart.
  • Duplicate, stale, malformed, foreign, and wrong-provenance reports do not advance the role.
  • Authoritative facts that may arrive in either order form an exactly-once join. Install-action settlement is discharged before any later proxy report, so that specific order is causal rather than guessed.
  • A contradictory stable-creation, worker-creation, worker-stop, or proxy-stop combination returns all conflicting facts without consuming the valid side of the join.
  • Expected command-unavailability reports from an owned proxy are relayed to the authored owner with role, sender, phase, and command intact.

[FS-OPERATE] Status, capability, and diagnostics

  • The public management protocol provides a typed status query without exposing private member-state variants or structural paths.
  • A status snapshot identifies every declared role and its supervisor-visible semantic phase: creating proxy, waiting for activation authorization, awaiting proxy outcome, ready, empty, recovering, stopping, or retired. It does not invent worker-creation or activation progress the proxy never reports.
  • A ready role's snapshot or capability query may return its exact stable proxy capability; non-ready roles return a typed availability result rather than a sentinel or absent capability paired with flags.
  • Request replies and durable lifecycle/diagnostic publication are separate route capabilities. A temporary query caller never silently becomes the owner of later events.
  • Omitting lifecycle-event publication never omits diagnostics. If diagnostic delivery is rejected, [SH-DELIVERY] requires the complete diagnostic to remain owned by the typed rejection path; it is never discarded or reclassified as a successful lifecycle event. The exact return-state equation remains a shared delivery-design blocker.
  • Querying does not mutate recovery budget, role order, readiness, or child ownership.

[FS-ELIGIBILITY] Restart eligibility

  • Permanent workers are eligible after normal or abnormal termination.
  • Transient workers are eligible only after abnormal termination.
  • Temporary workers are never automatically restarted.
  • Ineligibility retires or leaves empty according to the documented topology policy and is not reported as budget failure.
  • A supervision-failure exit is classified as abnormal for transient policy.

[FS-STRATEGY] Restart strategies

  • One-for-one selects only the triggering role.
  • One-for-all selects every currently restartable role.
  • Rest-for-one selects the trigger and currently restartable roles declared after it.
  • Selection uses declaration order and an immutable pre-transition snapshot.
  • A role that is unresolved, retired, stopping, or already owned by an admitted replacement cannot be selected as though it were ready.
  • An initially unresolved member required by a coordinated strategy is retained in the recovery decision until its exact proxy outcome resolves the readiness prerequisite; it is never silently excluded.
  • Overlapping failures and duplicate worker stops cannot duplicate a selected replacement or charge a second decision accidentally.
  • Every selected replacement preserves the concrete worker variant for its role.

[FS-BUDGET] Restart budget

  • The budget applies to complete admitted replacement decisions, not individual mutation steps.
  • A configured maximum of zero denies every otherwise eligible decision.
  • The time window boundary is inclusive.
  • Evidence older than the window is pruned before admission.
  • Future-dated evidence is not incorrectly discarded by an out-of-order fact; interpreter-authored monotonic timestamps that regress are typed rejection.
  • Rejected decisions do not partially charge the budget.
  • Atomic multi-role decisions are either admitted and charged once or rejected without charge.
  • Stored budget evidence remains bounded by the active window.
  • Aged-out attempts make capacity available again.
  • Denial reports the attempts in the window, requested replacement count, and configured maximum.
  • Every budget timestamp is supplied by the interpreter's monotonic clock at the authoritative lifecycle fact; workers and callers cannot choose it.

[FS-TIMING] Restart timing

  • Immediate timing satisfies only the timer prerequisite. A replacement input is emitted in the triggering transition only when readiness and activation authorization are also satisfied; otherwise the prepared definition waits.
  • Constant, linear, and exponential delays are one-based, checked, bounded, and reject zero or inverted configuration.
  • Delay arithmetic overflow is typed.
  • Each role's admitted recovery count advances with checked arithmetic. The count has no implicit reset; exhaustion is a typed denial rather than wrap, saturation, panic, or a fabricated delay overflow.
  • A delayed decision retains every prepared replacement definition until its exact timer fires or shutdown cancels it.
  • Timer identity and generation are exact correlation data.
  • A stale, duplicate, wrong-generation, or foreign timer cannot release a decision.
  • Timer arrival, readiness resolution, and activation authorization are three independent prerequisites. Their closed eight-state sum joins every admissible order exactly once; no pair of booleans or incomplete four-state join represents it.
  • An activation slot is reserved atomically with the replacement input and is released only by that proxy operation's atomic terminal outcome or by transferred forced-retirement ownership.
  • A delayed multi-role batch emits each selected replacement once and in declaration order.
  • Denied delayed replacement leaves the affected role retired or empty rather than stranded in an installing phase.

[FS-ATOMICITY] Factory and decision atomicity

  • Every selected worker definition is prepared before the first replacement command or member-state commit.
  • If any factory call rejects, no selected peer is partially reserved, stopped, replaced, or budget-charged.
  • Factory rejection identifies the semantic role and retains the typed factory error.
  • Replacement preparation never requires a no-op factory, callback, selector, or placeholder for an unaffected template.

[FS-FAILURE] Failure reaction

  • RetireMember retires the exact role whose topology can no longer be preserved and leaves unrelated live roles operating.
  • StopSupervisor begins an orderly drain of every owned stable proxy and ultimately selects the advertised terminal result.
  • Budget denial, backoff exhaustion, factory rejection, stable proxy death, and worker creation rejection each enter the configured reaction through a typed diagnostic.
  • The diagnostic is emitted before any terminal verdict in the same action.

[FS-SHUTDOWN] Fixed-supervisor shutdown

  • Shutdown drains only supervisor-owned stable proxies.
  • Unrelated application children and their creation facts remain untouched.
  • Both established and still-installing proxies are included in the drain.
  • A pending proxy installation is resolved without duplicate shutdown.
  • Delayed replacement batches are cancelled and never emitted after shutdown.
  • Final pending creation rejection completes shutdown even when ordinary failure policy would retire only one child.
  • Shutdown rejection preserves the exact proxy and rejection reason.
  • The final proxy stop selects normal supervisor termination after preserving all reports in that transition.

3. Dynamic supervisor

[DS-BUILD] Definition and protocol

  • Construction requires an explicit policy for unexpected worker exit and a maximum retained-entry capacity.
  • No fixed-child list, fixed factory, restart strategy, restart budget, or placeholder callback is required.
  • The public management protocol has typed start, stop, replace, and query commands.
  • Every command names a semantic management key and carries its concrete logical, established, or mixed reply route.
  • Start and replace carry complete owned worker definitions.
  • The management key is separate from every creator-local proxy and worker nonce.
  • Construction selects entry capacity, activation, activation-authorization limit, unexpected-exit, ActorDrainPolicy, one durable lifecycle route, and one diagnostic disposition. No temporary request recipient becomes the durable lifecycle owner, and no no-op callback or dummy route represents diagnostic termination.

[DS-START] Start

  • Start acceptance is distinct from committed installation.
  • A new key reserves one dynamic membership entry and stages one fresh stable proxy.
  • StartAccepted identifies the management key but does not claim the proxy or worker is installed.
  • Started is emitted only after the exact stable proxy capability is committed and the initial worker reports ready.
  • Started returns the exact established stable proxy recipient.
  • A duplicate key returns the submitted worker unchanged with AlreadyExists.
  • Start while global shutdown is in progress returns the worker unchanged with ShuttingDown.
  • Rejected stable-proxy creation returns a typed start failure and retires the reserved entry.
  • Rejected initial-worker creation returns a typed start failure and drains or retires the empty proxy without fabricating availability.
  • The start reply route is used only for the start request. The one durable lifecycle route selected on the supervisor builder owns every later realization, unexpected-exit, and proxy-unavailability event. Individual start requests cannot replace or transfer that owner.

[DS-QUERY] Query

  • Query returns Unknown for an unknown key; absence is a semantic outcome, not None paired with another phase field.
  • A known key returns one exhaustive public phase: reserved, creating proxy, waiting for activation authorization, awaiting proxy outcome, ready, empty, stopping, replacing, cancelling, draining, or retiring. The supervisor does not expose worker-creation or activation progress absent from ProxyReport.
  • Query never changes membership or lifecycle state.
  • Query during global shutdown reports the exact draining state rather than a guessed ready value.

[DS-STOP] Stop

  • Stop of an available or empty key is acknowledged as accepted and requests shutdown of that exact stable proxy.
  • Stop completion is reported only after the matching proxy exit.
  • Unknown, already retired, already stopping, or otherwise unavailable keys return typed rejection without state change.
  • Exact runtime shutdown rejection is returned with its capability reason and does not masquerade as admission rejection.
  • Stop waits for the exact pending proxy creation when invoked during start; it cannot send to an uncommitted child.

[DS-REPLACE] Replace

  • Replace is distinct from dynamic stop followed by a new key.
  • Replace retains the stable proxy and requests one fresh worker incarnation.
  • Acceptance is reported before realization.
  • The submitted worker is returned intact when the key is unknown, stopping, replacing, retired, or globally shutting down.
  • Replaced is emitted only after the replacement incarnation is ready.
  • Replacement rejection preserves exact creation reason and does not report success.
  • Replacement provenance names the exact prior worker incarnation.
  • Stop and replace wait for their exact runtime facts and cannot consume one another's report.

[DS-EXIT] Unexpected exit and unavailability

  • A matching unexpected worker stop makes the key empty before policy is applied.
  • KeepEmpty preserves the stable proxy for an explicit later replace.
  • Retire drains the stable proxy and retires the key.
  • A stale or foreign worker stop cannot vacate another key or incarnation.
  • Every unavailable proxy command is returned to the durable lifecycle owner exactly once with key, sender, phase, and command intact.
  • Unavailability is supported during installation, replacement, empty, stopping, and global shutdown phases.

[DS-RETENTION] Capacity, retirement, and key reuse

  • Reserving a new key at capacity returns the submitted worker unchanged with a typed capacity rejection.
  • Retired entries are removed after all proxy, activation, delivery, and shutdown facts for their exact entry generation are resolved.
  • A removed key may be started again with a fresh entry generation and fresh proxy; it is never address reuse or actor replacement.
  • Every delayed fact and private report carries enough exact generation and capability evidence that an earlier use of the same key cannot affect the new entry.
  • KeepEmpty entries continue to consume capacity; explicit Stop is required to drain the proxy and release the key.
  • The table retains no permanent tombstone. A late fact for a removed generation is returned as a typed stale diagnostic with its complete payload.

[DS-CANCEL] Accepted-operation cancellation

  • Start and replace acceptance return an opaque operation token distinct from the management key and actor nonce. Its constructor and fields are private, but the accepting caller can move the value into Cancel.
  • Operation phase is exhaustive: proxy creation emitted with actor-owned definition, proxy committed while waiting for activation authorization with actor-owned definition, install input emitted, awaiting the proxy's atomic outcome, ready, cancelling, or shutdown-owned.
  • Cancellation in a phase that still owns the definition returns it. Emitting an install/replacement input transfers the definition; no later outcome may claim to return it.
  • Cancellation after definition transfer is logical. It suppresses Started/Replaced, waits for delivery/creation/activation settlement, and drains any incarnation that commits or becomes ready.
  • Cancellation names that exact token and returns one exhaustive CancellationReceipt: Returned, Pending, Committed, Cancelled, Stale, or Draining.
  • Cancelling start drains any committed proxy after all transferred install and activation ownership settles. A late ready incarnation is never advertised.
  • Cancelling replacement never revives the old worker or reports replacement success. A late replacement incarnation is drained exactly once.
  • Stop is a lifecycle operation on the entry, not an alias for cancelling an unrelated start or replace token.

[DS-SHUTDOWN] Dynamic-supervisor shutdown

  • Global shutdown rejects new management mutation commands.
  • Every known installing, available, empty, replacing, or stopping stable proxy is resolved and drained exactly once.
  • Entries already removed from the table are absent and require no effect.
  • Pending creation rejection counts as drained.
  • The supervisor terminates normally only after every dynamic entry is retired.
  • Outer shutdown composition can deliver the shutdown input and interpret all dynamic outcome and child lifecycle lanes without path-specific caller code.

4. FIFO worker pool

[FP-BUILD] Definition and construction

  • Construction requires a worker factory, at least one unique semantic worker role, a complete recovery policy, a backlog capacity, an interruption policy, and FIFO distribution.
  • An incomplete definition cannot implement Behavior or call build.
  • A zero-worker pool is rejected before it can accept owned work.
  • Duplicate worker roles are rejected before initialization.
  • Factory rejection before activation emits no partial worker fleet.
  • The worker public message protocol must accept the pool's exact assignment product; a wrong worker protocol fails statically.
  • The customer reply protocol retains the exact job, result, role, admission, completion, and terminal-return outcomes selected by the pool.
  • Construction or application hosting selects a typed operational-diagnostic disposition. Expected diagnostics cannot disappear into an unnamed lane or require a no-op callback.
  • Construction also selects worker activation and ActorDrainPolicy; installation alone is never the implicit activation policy.

[FP-TOPOLOGY] Worker topology and recovery

  • The pool directly owns one fresh worker-incarnation sequence per declared semantic role; no stable proxy is required because workers are private to the stable pool actor.
  • Initial worker creation, worker stop, replacement, budget, timing, failure, and shutdown are interpreted by the pool's own fold.
  • Pool lifecycle handling is not delegated to a nested supervisor behavior or proxy whose events are redispatched.
  • Fresh worker replacement preserves the semantic pool role and future dispatch eligibility without preserving a worker address.
  • Every direct-worker member has exhaustive pre-ready phases for creation, installed initialization settlement, waiting for activation authorization, activation dispatched, and activating. Each phase owns only its exact definition, incarnation, settlement, permit, plan, or attempt.
  • Each pool owns one positive activation-authorization limit, a declaration-order waiting-role queue, and exact occupied tickets. An installed worker may wait with its activation permit and plan until authorization; it is never silently counted as activating.
  • Reserving a slot and emitting BeginActivation are one commit. Mandatory action settlement establishes accepted activation before the next ordinary pool input; the exact ready, rejected, stopped, or forced-transfer outcome releases the slot once.
  • Installed, waiting-for-authorization, dispatched, or activating workers remain ineligible for dispatch until their exact readiness fact commits.
  • Every transition that makes a worker ready first checks the applicable backlog. It commits Busy plus assignment of the oldest eligible queued job when one exists, and commits Idle only when none exists.
  • Post-commit initialization rejection, activation rejection, cancellation, and shutdown own distinct pre-ready drain causes; recovery or retirement begins only after exact terminal or forced-transfer settlement.
  • Worker-incarnation replacement never changes the role used for assignment.
  • Restart denial or irrecoverable worker loss cannot strand queued or assigned jobs.

[FP-ADMIT] Job admission

  • Submission carries a complete owned job, concrete customer reply route, and caller-authored request correlation echoed by both admission outcomes. The request correlation is never trusted as pool job identity.
  • The pool retains the customer route; it is never copied into the worker assignment or echoed back by worker code.
  • After classifying shutdown, serviceability, and full backlog, the pool assigns a fresh job id and immutable admission ordinal without trusting a customer-supplied id as either internal correlation.
  • If an eligible worker is idle, the job is accepted and assigned in the same transition.
  • Assignment state is committed before the dispatch effect is exposed.
  • If no worker is idle and backlog capacity remains, the job is accepted once and appended in FIFO order.
  • Capacity is the new-admission waiting bound and counts only jobs currently in the backlog; assigned work is owned by a busy worker state. Retry is not a new admission and may temporarily place one formerly assigned job per worker beyond that bound, so the absolute queue bound is capacity plus roster size.
  • Capacity zero is valid and permits only immediate assignment.
  • A full backlog returns the customer, reply recipient, and payload unchanged.
  • Full/unserviceable rejection occurs before job allocation. Job-correlation and immediate-dispatch preparation failures are distinct typed rejections; failure does not silently fall back to queue admission.
  • Admission during shutdown returns the owned job unchanged.
  • A payload clone needed for dispatch occurs before admission state commits. Unwind cannot leave a recorded assignment or dequeue because no transition was returned, but caller ownership recovery is not promised across panic.

[FP-ASSIGN] Assignment

  • Every dispatch carries a fresh opaque affine completion authority and owned job payload. The pool separately retains job id, customer route, exact worker role, and incarnation.
  • Token fields and constructors are private. Worker code can only move the token through assignment.complete(result); it cannot construct a token or choose a customer destination.
  • A job has exactly one authoritative customer obligation and active correlation at a time. Under Retry, the pool retains the canonical obligation/payload while a worker owns a cloned execution payload; those are deliberately two Rust values but never two customer completions.
  • No job is simultaneously queued and assigned.
  • No worker owns more than one assignment unless the worker protocol explicitly defines concurrency; the current template is single-assignment.
  • Idle-worker selection uses a circular declaration-order cursor. Each assignment selects the first ready idle worker at or after the cursor, skipping unavailable roles, then moves the cursor to the next surviving role. Becoming idle does not jump a worker ahead of the cursor.
  • Removing or retiring a worker does not reorder surviving FIFO jobs.
  • A dispatch batch preserves FIFO job order even when internal worker entries are removed.
  • Retry reinserts by immutable admission ordinal, not unconditionally at the front. Multiple interrupted workers therefore preserve their original admission order regardless of stop arrival order.
  • No serviceable queued job may coexist with an eligible idle worker. This invariant is restored in the same fold that processes initial readiness, replacement readiness, retry recovery, or completion; a later submission therefore cannot jump ahead of older backlog.
  • Rejected assignment delivery returns the exact worker command. A typed reunion consumes its affine completion authority with pool-retained evidence once before ordered reinsertion, then quarantines the exact worker for drain/recovery. This is safe return, not an at-least-once interruption; delivery settlement, completion, and worker stop may arrive in any order and join without a second job disposition.

[FP-COMPLETE] Completion

  • A matching completion authority resolves to exactly one active pool-owned record containing assignment id, job id, customer route, worker role, and private worker-birth evidence. The locked parent report supplies only the creator-local child nonce, so matching combines that nonce with opaque authority-carried birth evidence; it does not claim the interpreter attaches an exact incarnation capability.
  • Matching completion returns the result exactly once, releases that worker, and immediately dispatches the oldest eligible backlog job when present.
  • Duplicate completion is stale and cannot emit a second customer outcome.
  • Cross-worker completion is stale and cannot release either worker.
  • Completion from an old worker incarnation is stale and preserves the current assignment.
  • A stale completion returns the complete result through the separate operational-diagnostic disposition without mutating current ownership or sending another customer outcome.
  • Completion and successor dispatch effects coexist in one action without loss or reordering.
  • Completion may precede assignment-delivery settlement. Completion, settlement, and worker stop form one exhaustive order-independent join; no synchronous settlement guarantee is assumed.

[FP-INTERRUPT] Worker interruption

  • A worker stop matching an idle worker makes only that exact worker unavailable and enters recovery.
  • A worker stop matching a busy worker first resolves ownership of its exact assignment.
  • Fail returns the interrupted job exactly once with a typed interruption outcome.
  • Retry retains the complete job for at-least-once execution and reinserts it by its immutable admission ordinal. Queue metadata retains prior role and a semantic interruption classification, never a second copy of the authoritative stop fact.
  • Retry is explicitly at-least-once processing: the worker may have performed application work before stopping, so the pool does not claim exactly-once execution or side effects.
  • Clone preparation needed to retain a retry copy occurs before state commit. If cloning unwinds, no new pool state or Actions commit exists; the design makes no promise that Rust unwind restores caller ownership or prevents the actor from failing.
  • Worker stop, assignment settlement, completion, and worker creation facts that can arrive in different orders join exactly once without losing, duplicating, or prematurely failing the assignment.
  • Duplicate worker stop during replacement cannot cause a second retry or failure outcome.
  • A returned assignment after restart exhaustion or shutdown is consumed as stale without a second customer outcome.

[FP-FAILURE] Retirement and failure

  • An irrecoverably retired worker causes no future dispatch to that role.
  • Backlog work that can run on other FIFO workers remains eligible.
  • If no live or recoverable worker can ever serve queued work, every stranded job is returned exactly once with a typed terminal reason.
  • Pool failure diagnostics and customer job outcomes remain separate named effect lanes.
  • A supervision failure cannot be reconstructed from a missing worker or sequence arithmetic.

[FP-RETENTION] Correlation retention

  • Every accepted queued or assigned job retains its customer route. Only an active assignment retains full completion correlation; queued jobs have no completion authority.
  • Terminal customer outcome removes the active correlation after its delivery attempt is emitted; any rejected delivery follows [SH-DELIVERY] and is not reconstructed from a tombstone.
  • Completion tokens and assignment/job ids are never reused before typed exhaustion, so an old token cannot match a later job.
  • The pool retains no unbounded ReturnedAssignment tombstone table.
  • A completion for a non-active token is an unknown/stale operational diagnostic carrying the result; it cannot select a customer.

[FP-SHUTDOWN] FIFO-pool shutdown

  • Shutdown immediately removes and returns every queued job exactly once.
  • Every assigned job is returned exactly once according to the documented shutdown outcome; later completion is stale.
  • No retry or successor dispatch is emitted after shutdown begins.
  • Pending worker creation and delayed recovery are resolved or cancelled without losing jobs.
  • Every owned worker incarnation is drained exactly once.
  • Worker stop and completion in either admissible order complete the drain without duplicate job outcomes.
  • The pool terminates normally only after every job has been returned or completed and every owned worker is drained.

5. Keyed worker pool

Keyed pooling reuses only the FIFO laws listed here. No unlisted FIFO requirement is inherited implicitly.

ConcernShared FIFO lawKeyed substitution or restriction
Direct workersFresh direct-worker creation, exact readiness, one active assignment per worker, and complete lifecycle/drain ownership apply.Each worker has one immutable semantic role; no proxy or supervisor state is reused.
Customer ownershipOne authoritative obligation, correlated admission outcome, opaque completion authority, typed assignment-delivery settlement, and one terminal customer outcome apply.Accepted work additionally retains non-authorizing admitted-binding evidence { generation, role }; it does not retain or clone the submitted key.
Queue orderImmutable admission ordinal and retry reinsertion by that ordinal apply.There is one FIFO queue per role. A role's retry may add at most its one formerly active assignment beyond that role's admission bound, for an absolute per-role bound of capacity + 1. There is no global retry-overflow equation.
Dispatch eligibilityOnly exact ready-idle workers are immediately assignable, and readiness cannot leave older serviceable work queued.The retained role selects the only candidate worker. The no-serviceable-backlog invariant is scoped to that role; another idle role cannot serve it.
Worker selectionNone.There is no circular worker cursor or cross-worker scan. Binding/selection chooses a role before dispatch.
CapacityZero backlog means immediate assignment only.Backlog capacity is per role, and binding-table capacity is a separate positive bound. There is no global backlog capacity.
Recovery and interruptionRecovery eligibility, exact lifecycle correlation, Fail, explicit at-least-once Retry, and complete stranded-work return apply as value laws.Recovery and retry preserve the admitted role. Rebalance cannot retarget accepted work.
Shutdown and settlementAdmission closes, every accepted job settles once, workers drain exactly once, and action/rejection settlement remains explicit.Every role partition is extracted, all bindings are removed, and late keyed management/completion facts are generation-classified.

[KP-BUILD] Definition and selector

  • Construction requires one concrete statically dispatched selector.
  • FIFO construction requires no selector, placeholder selector, or no-op policy.
  • Every keyed submission carries its semantic key separately from its owned payload; the payload implements no pool-specific key trait.
  • The selector maps the submitted key to a semantic worker role, never to an actor nonce or address.
  • Captured selector state remains concrete and statically dispatched.
  • Selection is evaluated once at admission and its chosen role is retained by accepted work.
  • Construction selects a per-role backlog capacity and a maximum number of retained key bindings. No ambiguous global backlog capacity is inferred.

[KP-AFFINITY] Affinity and admission

  • A valid binding routes new work only to the selected role's worker incarnations.
  • Fresh worker-incarnation replacement preserves affinity automatically.
  • If the selected role is busy, only that role's backlog capacity determines targeted admission.
  • Work bound to one role is never stolen by another idle role.
  • A retired selected role refuses new work with the complete owned job.
  • Committing permanent unavailability for one affinity role terminates that role's queued and assigned work without disturbing live roles or their jobs.
  • Target eligibility is an exhaustive admission sum: AssignableNow, BacklogAdmissible, or Unavailable. The total projection covers every private member variant and every pre-ready drain disposition; no state falls through to a default branch.
  • Ready-idle is AssignableNow. Prepared, creating, initializing, waiting-for-authorization, activation-dispatched, activating, ready-busy, and admitted recovery are BacklogAdmissible. Stopping, retired, and shutdown-owned are Unavailable. DrainingPreReady projects by its retained exhaustive after-drain sum: recover or retire. Irrecoverability is a transition cause that commits a permanently unavailable phase, not a second retained member state.
  • A key with no retained binding is selected once by the concrete selector and bound atomically with accepted admission when binding capacity permits and the target is either immediately assignable or backlog-admissible with remaining per-role capacity. Rejection, including zero-capacity backlog for a non-idle target, retains neither the job nor a new binding.

[KP-REBALANCE] Rebalance

  • Rebalance is an explicit typed command.
  • Every rebalance carries Absent | Exact(binding_generation) expectation. Rebalance of an absent key requires Absent; rebalance of an existing key requires its exact current generation.
  • A valid rebalance changes future admission only.
  • Already queued and assigned jobs retain the role chosen when they were accepted.
  • Rebalance target eligibility is a separate exhaustive projection. Prepared, creating, initializing, waiting-for-authorization, activation-dispatched, activating, ready-idle, ready-busy, admitted recovery, and pre-ready-draining-with-ResumeRecovery are bindable. Stopping, retired, terminal pre-ready drain, and shutdown-owned are unavailable. An unknown or unavailable target returns the complete request and preserves the prior binding.
  • An explicitly unbound key can be bound by a valid rebalance.
  • A role-changing rebalance reserves a fresh generation before atomically replacing the old binding. A same-role rebalance is an accepted no-op that preserves the current generation.
  • Stale absence or generation expectation returns the complete command unchanged and cannot validate or mutate a later binding.
  • Repeated and short rebalance sequences match an independent binding model.
  • Rebalance never creates, replaces, revives, or proves a worker actor.
  • Explicit Unbind removes only the future-admission binding. Already queued and assigned work retains its selected role.
  • Unbind of an existing key requires its exact current generation. A stale absence or generation expectation returns the complete command unchanged.
  • Unbinding an absent key returns typed AlreadyUnbound { key } and leaves state unchanged. Idempotence is an explicit protocol outcome, never guessed from map mutation success.

[KP-END] Keyed completion, interruption, and shutdown

  • Completion correlation includes the retained affinity role in addition to assignment, job, and incarnation.
  • Retry returns interrupted work to the same retained role unless a separate explicit policy says otherwise; rebalance does not retarget it.
  • A permanently retired role's returned work cannot later be revived by a stale lifecycle or completion fact.
  • Shutdown returns jobs from every affinity partition exactly once and drains every owned worker incarnation.
  • Assignment, customer response, lifecycle, recovery timer, and shutdown lanes remain independently named and are all interpreted at the same actor path.

[KP-RETENTION] Binding retention

  • Binding capacity counts only currently retained key-to-role bindings, not queued jobs or active assignments.
  • Rebalance does not allocate a second binding entry for an existing key.
  • Unbind releases capacity immediately because queued/assigned jobs retain their role independently.
  • A later submission for the same unbound key invokes the selector again and creates a new binding generation.
  • Late rebalance/unbind outcomes are correlated to the binding generation so they cannot modify a later reuse of the same key.
  • The transition committing permanent unavailability atomically unbinds every retained binding to that role, releases their binding capacity, and emits one typed diagnostic per removed key/generation. Irrecoverable is one cause for that transition, not a retained terminal phase beside Retired. Temporary recovery and pre-ready drain with ResumeRecovery retain bindings. Already queued or assigned jobs retain admitted-binding evidence needed for their single terminal outcome; no permanently unusable binding remains.

[API] Builder and public API requirements

  • Builders encode missing versus selected semantic choices in their types.
  • Builder values do not implement Behavior.
  • Only complete built definitions implement Behavior.
  • Value-dependent invalidity, such as duplicate roles or invalid delay bounds, returns a typed build error.
  • Builders never request child nonces, timer ids, assignment ids, job ids, or actor addresses from the caller.
  • Fixed, dynamic, FIFO, and keyed construction expose only choices meaningful to that template.
  • No valid construction requires a no-op callback, dummy selector, empty factory, marker route, explicit output alias, wrapper path, or generic type annotation whose only purpose is satisfying internal machinery.
  • Resulting behavior types are inferable from ordinary factory, role, selector, worker, and reply values.
  • Public names describe semantic state, policy, command, result, or error—not structural positions such as inner depth or wrapper ownership.
  • Each template has one documented fluent order. Typestate exposes only the next meaningful choices; arbitrary equivalent call permutations are not a second advertised API.
  • Ordinary construction requires neither explicit reply-protocol aliases nor turbofish that repeats types already present in factory, worker, selector, route, or command values.
  • Infallible and fallible worker construction are both truthful: an infallible factory does not manufacture an Option/error branch, and a fallible factory preserves its exact typed error.
  • Worker code completes a pool assignment with assignment.complete(result). It never names ReportToParent, a parent path, customer recipient, assignment id, or send-product lane.
  • Every template has one complete copy-paste example covering imports, worker definition, construction, hosting, activation/readiness, command or job submission, replies/diagnostics, and shutdown.
  • Compiler diagnostics are measured with focused compile-pass/fail fixtures; the typestate syntax remains a hypothesis until those fixtures show the error at the missing semantic choice rather than in nested associated types.

[EFFECT] Effect and interpreter requirements

Each template exposes one named effect product containing only lanes it can actually emit. Across the catalogue these include:

  • worker-command deliveries;
  • private parent-to-proxy installation and replacement inputs;
  • proxy and worker creation observation;
  • proxy and worker termination observation;
  • exact child shutdown requests;
  • restart scheduling requests;
  • parent lifecycle and unavailability reports;
  • dynamic management replies;
  • pool worker assignments;
  • pool customer outcomes; and
  • supervision or pool terminal diagnostics.

Requirements:

  • Every lane has a concrete static interpreter requirement.
  • Interpretation order is documented and tested.
  • Same-action creation is committed before any bundled creation observation, child-termination observation, child delivery, child input, or child shutdown.
  • Every current same-action occurrence-dependent operation is owned by one staged creation-scoped bundle: ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild. The bundle explicitly selects direct creation → occurrence effects or creation → required observations → occurrence effects. Independent effects remain outside; no dependency is inferred from lane position, wrapper path, role, or lookup.
  • Creation rejection produces one authoritative prerequisite settlement and returns every bundled observation/delivery/input/shutdown untouched as NotAttempted. After accepted creation, every required observation is attempted in named lane/item order even when another rejects, and every rejection is preserved independently. All later occurrence effects become NotAttempted with the first rejected observation in that order as their deterministic blocked_by prerequisite. A future occurrence-dependent operation must extend the closed bundle and tests before same-action use. Independent effects still run.
  • ObserveEstablishedCreation belongs to the bundle because its input is the pre-commit child route and its result supplies the exact committed capability. Established delivery, observation, and shutdown cannot enter because they require that capability as input; logical delivery is occurrence-independent and child reports originate from the child. These inclusions and exclusions are part of the completeness proof.
  • One lane's interpreter failure does not allow a later lane to pretend an earlier required effect succeeded. A dependent item settles as NotAttempted; an independent item is still interpreted.
  • Append and reducer operations preserve every lane, creation, and terminal verdict exactly once.
  • Fixed and heterogeneous birth products dispatch to concrete installers without erased runtime selection.
  • A minimal interpreter witness consumes every lane of every atomic template.
  • Every delivery lane also has an interpreter-rejection witness satisfying [SH-DELIVERY]; a success-only interpreter does not implement the template.

[VERIFY] Required verification per template

Each atomic template must have:

  • focused example tests for every transition above;
  • compile-pass tests for complete builder syntax;
  • compile-fail tests for incomplete builders and protocol mismatch;
  • complete-action assertions, not effect counts alone;
  • both event orders for every legitimately unordered fact join;
  • independent model tests using vocabulary different from production state;
  • exhaustive small-state tests for lifecycle, budget, backlog, binding, and shutdown boundaries;
  • property tests asserting invariants after every generated step;
  • fuzz coverage for stale, duplicate, contradictory, overlap, and shutdown sequences;
  • debug and optimized regressions for lifecycle facts that must not be accepted twice; and
  • an interpreter-level witness for initialization ordering and every named lane.
  • readiness/activation races, delivery rejection, bounded retention, key reuse, and deadline-retirement tests where those laws apply.
  • exhaustive keyed-admission projection over every member and after-drain variant, with no wildcard model branch;
  • readiness, recovery, and completion sequences proving that serviceable backlog never coexists with eligible idle capacity;
  • a root-driver trace in which actor-side forced retirement occurs before late activation readiness, followed by exact incarnation drain and only then the final runner result;
  • compile-pass/fail terminal lifts for heterogeneous children, duplicate role values, and one/two/eight wrapper layers with a recorded diagnostic-size bound; and
  • interpreter traces for accepted/rejected creation and required observation, covering ObserveCreation, ObserveEstablishedCreation, ObserveChild, child delivery, child input, and child shutdown while proving dependent NotAttempted values and continued independent effects; the traces must include multiple required-observation rejections and prove that all are preserved while downstream items reference the first rejection in named interpretation order.

The original defect must be demonstrably reproduced by each regression it is intended to prevent. A green build without that counterexample is not evidence that the feature is implemented.

[NONFEATURE] Existing surfaces that are not features

The replacement need not preserve these implementation artifacts:

  • arbitrary Behavior supervision wrappers;
  • fluent extension methods;
  • BehaviorLayer construction of supervisors or pools;
  • FixedFleetOwnership, slot products, ownership redispatch, or positional nesting paths;
  • a pool implemented by nesting or forwarding another pool;
  • duplicated flattened copies of another template's effect product;
  • a public utils module;
  • a mandatory policy whose only legitimate implementation is a no-op; or
  • compatibility aliases that keep both old and new architectures alive.
  • stable proxy children inside a pool, because the stable pool actor already owns private worker incarnation routing.

Their observable laws are included above where required. The artifacts themselves are deleted after the replacement templates and migrations are proven.

Minimal type equations and actor relationships (engineering record)

This document derives types from the feature catalogue. It deliberately does not turn every phase, error reason, effect lane, builder axis, or compiler obligation into a public type.

The previous 64-name inventory is withdrawn. It confused four categories:

  • semantic values a user deliberately chooses or observes;
  • behavior definitions and public protocols;
  • private state-machine proof types; and
  • generated/interpreter plumbing.

Only the first two categories are candidates for the ordinary public API. Private sums remain real sums—they are not converted to flags—but their names do not become concepts users must import.

This document is not a second runtime-state specification. The sole normative ownership equations and legal transitions are in atomic-actor-solution.md. If a candidate public protocol described here cannot be projected from those equations without losing ownership or provenance, the candidate is invalid; the inventory does not amend the runtime state machine.

Minimization test

A new public type is allowed only when all four answers are concrete:

  1. Which distinct semantic state, outcome, or capability does it own?
  2. Which invalid exchange or transition becomes impossible because it is a separate type?
  3. Why can an existing core type or a variant of an existing actor protocol not express it?
  4. Which caller-written type, alias, marker, route, or callback does it remove?

The following do not justify a public type: naming a generic parameter, shortening a nested type, satisfying a bound, forwarding an event, hiding a structural path, or making rustdoc look symmetrical.

Visibility budget

There are four visibility bands.

BandContentsOrdinary user names it?
Public semanticactor builder/definition, command/outcome sums, real policy sumsYes
Public but inferredprotocol identity and typestate return forms whose exact spelling is compiler-prototype dependentNormally no
Crate-private semanticexhaustive runtime phases, joins, correlations, tickets, drain statesNo
Generated/interpreternamed effect products, occurrence positions, request lanes, lowering traitsNo

If the compile prototype makes the last two bands appear in ordinary source, the DevX is rejected. They are not promoted to public concepts to make the prototype compile.

Existing core: seven retained concepts

The exhaustive decision is in atomic-actor-retained-core.md. The atomic actors reuse only these irreducible concepts: Protocol, Behavior, Actions, Step, logical/exact recipients, staged CreateChild, and TerminalOutcome. Current support and interpreter carrier types may remain internally, but the actor modules do not duplicate or re-export them.

Shared public semantic values

These are shared only because every consuming actor gives them the same law. There is no shared runtime ownership engine.

Recovery

Permanent { strategy, limit, release }
Transient { strategy, limit, release }
Temporary
  • Owns the complete eligibility and replacement decision policy.
  • Temporary cannot accidentally carry unused restart settings.
  • Used by fixed supervisor, FIFO pool, and keyed pool.
  • Dynamic supervision does not use it; replacement there is an explicit management operation.

Strategy

OneForOne | OneForAll | RestForOne
  • Selects an ordered candidate set from one immutable topology snapshot.
  • Shared by the three actors that use Recovery.

RestartLimit

{ maximum: u32, window: Duration }
  • Owns atomic sliding-window admission.
  • The catalogue defines the exact zero, boundary, monotonic-time, and out-of-order laws; no boolean “within limit” escapes the fold.

RestartRelease

Immediate
Constant { delay }
Linear { initial, maximum }
Exponential { initial, maximum }
  • Combines timing and backoff in one sum; there is no optional backoff or separate timing flag.
  • Checked construction rejects zero delay and maximum below initial.
  • Delay arithmetic is checked and its failure is a typed denial outcome.

ActorDrainPolicy

WaitForActorGraph
RetireActorGraphAfter { deadline }
  • WaitForActorGraph makes potentially indefinite actor-graph waiting an explicit choice.
  • RetireActorGraphAfter schedules an interpreter-clock deadline and produces exact forced-retirement facts for every unresolved child/job. It bounds only actor-graph retirement; transferred uncancellable work keeps the root run future alive.
  • If later requirements prove more than one deadline-retirement action, this sum gains semantic variants; it does not gain booleans.

This is not a process-exit policy. Final application completion separately requires residual root settlement to become empty. No bounded process-exit or emergency-abandonment policy is selected.

Activation and diagnostic choices

Activation has two semantic modes: immediate readiness after initialization, or a concrete statically dispatched activation plan resolved through the exact request/fact capability in the solution. The plan type is inferred from the value supplied to .activation(...); the inventory does not authorize a boxed callback, erased future, universal activation trait object, or a public type per activation phase. Nor does it authorize Activation<Plan>::Immediate, which would leave an unused plan type to infer; immediate and plan-bearing builder states must both remain inferred.

The activation-authorization limit uses ActivationPolicy, constructed from a plain usize with typed ZeroCapacity rejection. Its one user-facing law is “at most this many owner authorizations may be unresolved.” A supervisor conservatively records authorization when it emits the opaque proxy install input because the proxy exposes no progress facts. A direct pool records it when initialization has settled and it emits BeginActivation. The counting law is identical; the template-specific authorization boundary is explicit. A separate activation-limit spelling is not justified. Nor is there a second ActivationAuthorization capability: the exact installation-issued permit authorizes BeginActivation, while crate-private waiting variants and occupied tickets prove the concurrency bound.

Diagnostic disposition is one real semantic sum because its alternatives carry different capabilities:

Diagnostics<Route> = DeliverTo(Route) | Terminate

The notation does not authorize a literal generic enum: its Terminate variant would leave Route unconstrained. The builder must infer a route-bearing concrete state for DeliverTo or a route-free concrete state for Terminate; whether either policy type is an ordinary public name remains a compile-prototype question. It replaces mandatory .diagnostics_to(...); absence is not encoded by an Option, and autonomous actors terminate on a diagnostic without a dummy route or type annotation.

Per-item action settlements, activation attempts, installed incarnations, and rejection products are interpreter-facing typed capabilities. Ordinary application code does not construct them, but they are not erased or dynamically dispatched.

Open terminal and dependency boundary

TerminalSettlement now has a semantic equation but is not yet an authorized universal public type. One concrete application/root terminal sum must receive total statically dispatched lifts from every heterogeneous child and wrapper terminal sum while preserving exact provenance. Duplicate semantic roles do not identify a source. The solution's Static terminal-projection equation is normative; its Rust spelling remains Open until wrapper-depth diagnostics and heterogeneous lifting are compile-proven.

NonEmptyResidualSettlement is crate-private root-run state. It keeps exact external activation and late-drain ownership alive after the actor graph is forcibly retired. The final runner result does not exist until that state is empty; ordinary users receive no cloneable residual report or topology product.

CreationBundle<CreateRequest, AfterCreation> and LoweredAction<Independent, Creations> are semantic names for the selected interpreter dependency equation, not approved ordinary imports. Each bundle owns one creation and the closed current occurrence-dependent set: ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild. Its sum selects effects that depend directly on creation or also on required-observation acceptance. Every required observation is attempted in named lane/item order; if several reject, every rejection is retained and later NotAttempted effects reference the first rejection in that order. This replaces positional dependency discovery and runtime lookup. A core prototype must determine whether existing named Actions products lower truthfully or need a minimal interpreter-facing product change.

Why there are no shared public builder markers

Missing/present and empty/non-empty proofs are typestate implementation details. One internal proof family can serve every builder, but ordinary users must not import Unset, Set, NoMembers, Members, WithEvents, or a type per axis. The compile-pass/fail prototype must discover whether Rust can keep those states inferred. If not, the builder spelling is still open.

1. Stable proxy

Current public surface

  • StableProxy<Worker, Plan> — the behavior definition and stable service identity. StableProxy::immediate() and StableProxy::activated() are its two inferred constructions.
  • ActivationPlan, ImmediateActivation, and WorkerSubmission — application worker definition and its concrete activation work.
  • ProxyPhase, ProxyOutcome, InitialWorkerOutcome, ReplacementOutcome, and ProxyDiagnostic — owner-observable lifecycle and diagnostic products.

The service protocol is exactly the worker protocol. Owner control, initialization and activation requests, effect products, operation correlation, drain custody, and settlement inputs remain technically public only where the associated Behavior/interpreter contract requires them; they are doc-hidden and are not part of Bombay's ordinary facade.

Runtime ownership reference

The proxy performs one direct fold. Its complete Dormant, creation/stop, initialization/stop, activation/stop, ready, replacement, and drain equations are normative only in the solution's Stable worker proxy solution. In particular, the worker definition is transferred when the creation action is emitted; no inventory shorthand may place it back in a later creation state. “Atomic” means one local state/action commit, not atomic cross-actor delivery.

2. Fixed supervisor

Current public surface

  • fixed(...) and FixedSupervisor<…> — the one inferred construction and resulting behavior. The returned FixedBuilder is doc-hidden because ordinary source never names it.
  • OrderedRoles and DuplicateRole — validated non-empty unique topology.
  • ActivationPolicy, Recovery, FailureReaction, and ActorDrainPolicy — every required supervisor policy.
  • FixedCommand — status, capability, and shutdown management.
  • FixedSnapshot — read-only role/order/phase/availability projection.
  • FixedLifecycle — durable lifecycle outcomes only when .publish_lifecycle(route) is selected.
  • FixedDiagnostic — exact operational failures selected by DiagnosticDisposition.
  • InitialWorkerRejection — shared construction-only worker rejection with the function, prepared prefix, exact role/reason, and untouched suffix.
  • FixedConstructionRejected — fixed policies plus one InitialWorkerRejection.
  • FailureReaction — RetireMember | StopSupervisor; one exhaustive response when fixed topology can no longer be preserved.

Lifecycle publication is optional. An autonomous supervisor is a complete valid actor and provides no discard callback or dummy recipient.

The selected names are FixedCommand, FixedSnapshot, FixedLifecycle, and FixedDiagnostic. Construction and preparation rejections retain their exact typed values. Request products, internal events, lifecycle-route traits, and worker-preparation action products are doc-hidden interpreter contracts.

Builder semantic state

factory
ordered non-empty role declarations
Recovery
fixed-topology failure reaction: RetireMember | StopSupervisor
activation policy
positive activation-authorization limit
ActorDrainPolicy
diagnostic disposition
optional lifecycle DeliveryRoute

Only typestate proof markers are internal. Duplicate roles and factory rejection are value failures returned by build; construction performs no actor effect.

Runtime ownership reference

The solution's Fixed supervisor solution is the sole member, recovery transaction, activation-authorization, and drain equation. The decision is prepared completely before the supervisor commits any member reservation. Factory rejection, budget denial, overlap, clock regression, or timer exhaustion returns every value still owned at that phase in one typed outcome.

Different workers may be different behavior variants behind one closed worker sum only when they expose one common public service protocol. Workers with different public protocols require separate supervisors; the design does not erase them into a universal envelope.

3. Dynamic supervisor

Current public surface

  • DynamicSupervisor<…> — one keyed behavior that creates proxies.
  • DynamicCommand<Key, Worker> — Start, Replace, Stop, Query, and Cancel, each retaining submitted values.
  • WorkerChangeReceipt<Key> and WorkerChangeRejection<Key, Worker, Reason> — the shared start/replace result products; the rejection reason remains operation-specific.
  • CancellationReceipt<Worker> — the exhaustive affine cancellation result.
  • QueryReply<Key> — the exhaustive known/unknown read-only result.
  • DynamicLifecycle<Key, Worker, Plan> — durable later readiness, unavailability, cancellation, and retirement reports sent to the configured lifecycle owner.
  • DynamicDiagnostic<Key, Worker, Plan> — exact operational contradictions and runtime rejections handled by the independently selected diagnostic policy.
  • UnexpectedExit — KeepEmpty | Retire; the complete policy after an unrequested exact worker stop.
  • EntryCapacity — the positive maximum retained keyed entries. It is distinct from ActivationPolicy, so exchanging the two policies does not compile.

Request replies and durable lifecycle events use distinct protocol capabilities. A temporary request caller never becomes the long-lived owner by accident.

Command and operation sums

Start { key, worker, reply_to }
Stop { key, reply_to }
Replace { key, worker, reply_to }
Query { key, reply_to }
Cancel { operation, reply_to }

Start and replace use the same result equation without a naming alias:

Result<WorkerChangeReceipt<Key>, WorkerChangeRejection<Key, Worker, Reason>>

Accepted operations return a supervisor-issued opaque cancellation authority. Cancellation is then exhaustive within CancellationReceipt:

Returned { authority, worker }
Pending { authority, phase }
Committed { authority, resulting_phase }
Cancelled { authority }
Stale { authority }
Draining { authority }

Runtime ownership reference

AA-20 and the normalized dynamic document are the sole entry-state and cancellation ownership equation. Transaction-local preparation reserves every correlation before committing the creating-proxy entry and its creation action; there is no stored or queryable reservation phase. The state distinguishes emitted proxy creation, committed proxy waiting for activation authorization, emitted install, awaiting one atomic proxy outcome, readiness, cancellation, drain, and retirement. Worker creation and activation remain proxy-private. Only phases that still own a worker definition may return it.

The table has a configured maximum. Stop drains a ready or empty entry and eventually removes it; reuse of the same key creates a fresh generation. Facts from earlier generations are stale diagnostics and cannot mutate the new entry. No permanent tombstone is required.

4. Shared pool values

Only values with identical FIFO and keyed meaning are shared.

Assignment<Job>

{ payload, opaque_completion_authority }
  • Delivered to one exact worker incarnation.
  • Token fields and construction are private.
  • Consuming assignment.complete(result) creates the only valid completion.
  • Issuance creates an affine worker-held authority and pool-retained non-authorizing comparison evidence; retained evidence cannot manufacture a completion.
  • The authority is privately bound to one worker-birth evidence value. Worker code cannot inspect it; rejected assignment delivery returns the authority for typed reunion with the pool half.
  • Contains no customer recipient, parent path, role, job ID, or public token constructor unless the pool itself needs those fields privately.

Completion<Result>

{ result, consumed_completion_authority }
  • Moves from worker to owning pool.
  • Cannot select or substitute a customer destination.
  • The locked parent report supplies a creator-local child nonce. That nonce, authority-carried private worker-birth evidence, and the retained pool half must all match the active assignment before completion commits.

Interruption

Fail | Retry
  • Fail returns the accepted payload to the customer once.
  • Retry is explicitly at-least-once execution because the pool retained a retryable payload before assignment.

Customer and diagnostic protocols

The customer outcome is one closed sum:

Accepted { request: RequestCorrelation, job: JobId }
Rejected { request: RequestCorrelation, payload, reason }
Completed { job: JobId, role, result }
ReturnedQueued { job: JobId, payload, reason }
ReturnedAssigned { job: JobId, role, payload, reason }

A stale/duplicate/foreign completion is not another customer outcome. It goes to a separate operational diagnostic sum carrying the complete result, authority context, child nonce, private birth evidence, and reason. Its disposition is the builder's DeliverTo(route) | Terminate choice; it is never an unnamed lane, mandatory dummy destination, or no-op callback.

Whether customer acceptance and terminal outcome are one protocol or two capabilities remains a DX/type-safety prototype question. The law is fixed: one accepted job produces at most one terminal customer outcome.

RequestCorrelation is caller-authored and echoed only; the pool never trusts it as job identity or retains it after moving the admission outcome. JobId is an opaque public correlation value because a shared customer route must distinguish several accepted jobs; its constructor is private. AdmissionOrdinal, assignment IDs, completion authorities, private worker-birth evidence, and generations are private newtypes. Pool-owned issuers are non-wrapping, and the values remain distinct so one correlation kind cannot substitute for another.

5. FIFO pool

Current public surface

  • fifo(…) -> Result<FifoPool<…>, FifoConstructionRejected<…>> is the sole production construction spelling.
  • FifoPool<…> — one direct worker-owning fold.
  • FifoCommand, FifoOutcome, and their exact admission and return reason sums.
  • shared Assignment, Completion, Interruption, direct-pool recovery, drain, and diagnostics values above, plus the FIFO-specific BacklogCapacity.
  • one immutable private admission ordinal per accepted job; retry reinserts by ordinal rather than by stop-arrival order.

There is no Fifo marker, distribution mode, shared pool builder, policy bag, or build stage. The aggregate name and constructor already select FIFO.

Runtime ownership reference

The solution's FIFO pool solution is the sole worker initialization, activation authorization, job, completion, return, fairness-cursor, and drain equation. Outcome delivery is staged in the action settlement rather than represented as an invented Completing or Returning actor phase. Only active jobs exist in the table. After the single terminal customer action is committed, the active correlation is removed; settlement owns a rejected terminal outcome without recreating an active job or an unbounded tombstone.

6. Keyed pool

Current public surface

  • keyed(…) -> Result<KeyedPool<…>, KeyedConstructionRejected<…>> is the sole production construction spelling and does not reuse FIFO's constructor or a shared pool builder;
  • KeyedPool<…> — a separate direct fold, not a FifoPool wrapper;
  • KeyedCommand<Key, Job> — Submit { key, payload, reply_to }, Rebalance { key, expected, target, reply_to }, and Unbind { key, expected, reply_to }, where expected is Absent | Exact(binding_generation);
  • keyed management/customer outcome sum; and
  • one inferred concrete closure Fn(&Key) -> Role stored by the pool.

There is no public KeyedJob or SelectWorker trait. Submission supplies the key explicitly. The constructor statically stores one key-to-role selector without a boxed callback, selector trait, or second application-defined type.

Runtime ownership reference

The solution's Keyed pool solution is the sole binding, rebalance, unbinding, admitted-partition, and role-retirement equation. First accepted submission may create a generation-tagged binding after selector validation; an explicit rebalance with Absent expectation may also create a binding without work. The table stores only live bound entries, never a persistent unbound value. The binding is the sole owner of its key. Queued and assigned jobs retain copyable, non-authorizing { binding_generation, admitted_role } evidence rather than cloning or owning the key. Rebalance and unbind affect only future admission. Unbinding an absent key with Absent expectation returns the selected idempotent AlreadyUnbound { key } outcome.

Existing rebalance and unbind require Exact(current_generation). A role-changing rebalance prepares a fresh generation before replacing the old binding; a same-role rebalance is an accepted no-op preserving the generation. Every stale expectation returns the complete command unchanged. Rebalance uses its own total target projection: temporary recovery and pre-ready drain with retained recovery are bindable, while stopping, terminal drain, retained retirement, and shutdown ownership are unavailable.

Capacity and retention

  • There is no shared public Capacity sum. These are different domain laws, not interchangeable configuration values.
  • Dynamic-supervisor maximum entries is a mandatory positive EntryCapacity; an unbounded dynamic table is not a valid construction.
  • Backlog capacity is explicitly per role.
  • Pool backlog capacity is a usize because zero lawfully means immediate assignment only.
  • Binding-table capacity is a separate positive NonZeroUsize bound.
  • Unbind removes only future-admission affinity and releases binding capacity; already queued and assigned jobs retain their admitted role and generation.
  • Reusing a key creates a fresh binding generation.
  • Completion/rebalance facts from earlier generations are diagnostics only.
  • The transition committing permanent role unavailability unbinds every retained binding to that role, releases capacity, and emits exact key/generation diagnostics. Irrecoverability is a cause, not a retained terminal phase beside Retired; temporary recovery retains bindings. Existing work keeps its admitted evidence only until its terminal outcome.

Worker, job, recovery, and drain states are keyed-pool-private even where their variant names resemble FIFO. Sharing a runtime state type is allowed only after both folds prove identical ownership and transitions; similarity is not proof.

Actor topology and dependency direction

FixedSupervisor ──creates/controls──▶ StableProxy ──creates──▶ Worker
DynamicSupervisor ─creates/controls─▶ StableProxy ──creates──▶ Worker

FifoPool  ─────────────creates/assigns/observes directly─────▶ Worker
KeyedPool ─────────────creates/assigns/observes directly─────▶ Worker
  • Proxy depends only on the retained behavior algebra and neutral interpreter carriers.
  • Fixed and dynamic supervisors depend on proxy; neither depends on a pool.
  • FIFO and keyed pools contain neither supervisor nor proxy and do not contain one another.
  • Shared recovery/pool values are pure semantic values, never an engine.
  • All five templates are direct Behavior folds. They are not assembled from BehaviorLayers or a universal ownership utility.
  • crates/behavior never depends on an actor template.

Types deliberately absent

  • no Supervisor<Mode> or Pool<Mode> runtime engine;
  • no shared Member, Slot, Fleet, Ownership, or Children runtime;
  • no utils module;
  • no public WithParent, Inner, AtPath, occurrence, or effect-lane path;
  • no public typestate marker per builder axis;
  • no customer route inside an assignment/completion;
  • no optional selector in FIFO;
  • no stable proxy in either pool;
  • no public nonce, timer, job, assignment, operation, token, or generation constructor;
  • no callback/boolean where a semantic sum owns mutually exclusive choices;
  • no compatibility wrapper retaining legacy and replacement templates.

Selected public surfaces

FamilyComponent constructionStatus
Stable proxyStableProxy::immediate() or StableProxy::activated()selected
Fixed supervisorfixed(...), optional lifecycle publication, then build()selected
Dynamic supervisordynamic(entries, activation, unexpected_exit, actor_drain, lifecycle, diagnostics)selected
FIFO poolfifo(factory, roles, activation, recovery, backlog, interruption, actor_drain, diagnostics)selected
Keyed poolkeyed(factory, roles, selector, activation, recovery, backlog, bindings, interruption, actor_drain, diagnostics)selected

Generated component rustdoc lists 102 semantic items for the five implemented families: 43 structs, 53 enums, two traits, and four construction functions. These are construction, policies, commands, capabilities, typed rejections, and domain outcomes—not structural actor machinery. Reduce this count only when two names own the same law; hiding a real outcome is not surface curation.

There is one external component path: behavior_actors::atomic::Name; the crate root exposes zero duplicate atomic paths. Interpreter reexports are doc-hidden at the facade or at their definitions. Generated rustdoc excludes sampled effect products, request products, internal events, worker preparation, activation operations, proxy control, and settlement carriers. They remain statically reachable but are not candidates for Bombay's ordinary facade.

Bombay must selectively re-export only the semantic categories in atomic-actor-devx.md. It must not glob the component module or expose request products, internal events, effect products, preparation state, activation requests, proxy control, or settlement carriers.

All five component construction paths are selected. Bombay's selective facade, role-first application assembly, and runtime settlement/custody changes remain upstream integration work rather than component public-name questions.

Minimal core used by atomic supervisors and pools (engineering record)

This is a deletion audit, not a preservation promise. “Already in core” is not a reason to keep a type, and “the compiler needs a name” is not a semantic law. The atomic actors should expose their own domain protocols while depending on the smallest common actor algebra underneath them.

There are three different questions which must not be collapsed:

  1. what is irreducible actor algebra;
  2. which existing interpreter carriers are still needed internally; and
  3. which names an atomic-actor user must see.

Most of the current names belong only to the second category. They must not be re-exported as supervisor/pool concepts or counted as atomic-template types.

A. Irreducible retained algebra

These existing concepts have independent laws. The five atomic actors use them directly and must not recreate them in actors.

Existing conceptRetention law
ProtocolA nominal, statically known address/message identity. Equal Rust field shapes do not make two protocols interchangeable.
BehaviorPure initialization and one-communication fold. No executor, clock, hydration, or delivery occurs inside it.
ActionsThe sole successful effect boundary: typed communications, staged fresh creation, and next behavior/termination.
StepExhaustive continuation/become/stop verdict. Stopped and Never are supporting proof types, not new template concepts.
Recipient and EstablishedRecipientDistinct logical and exact delivery capabilities. One must never be silently widened into the other.
CreateChildOne staged fresh-child request with explicit provenance. It never means replacement or successful installation.
TerminalOutcomeOne authoritative terminal fact, preserving normal exit versus crash provenance.

BehaviorBase, User, Births<Child>, NoBirths, CreationKind, Exit, and Crash are current representation/support types for those seven laws. They remain only while the existing algebra and interpreter need them. The atomic actor modules do not wrap, alias, or re-export them merely to make their own signatures look uniform.

This is the minimal retained semantic kernel. It is seven concepts, not the dozens of lifecycle and topology types currently visible in the crate.

B. Existing interpreter carriers used internally

The following values may be used to lower an atomic actor's Actions into the current interpreter. They are not components from which supervisors or pools are composed, and they are not automatically part of ordinary DevX.

Existing familyInternal useDecision
Address, EndpointAddressRuntime-owned identity and exact endpoint familiesKeep in the interpreter boundary; do not expose numeric identity in builders.
ChildRoute, ChildDelivery, ChildInput, ChildReportCreator-local exact child routing and source-attributed reportsUse only inside direct owner/child folds. A route is correlation, not actor identity.
InterpreterRequests, InterpreterRequestClosed typed scheduling, observation, shutdown, and structural-report laneKeep one generic request lane; do not add a supervisor request trait and a pool request trait.
ObserveCreation, CreationResolvedCommitted or rejected staged creation without an exact endpoint capabilityReuse internally where only that fact is required. Do not add template-specific WorkerCreationResolved.
ObserveEstablishedCreation, EstablishedCreationSame-action committed or rejected creation with the exact installed capabilityReuse internally for stable proxies: fixed and dynamic supervisors must retain the exact committed proxy rather than reconstructing it from an address.
ObserveChild, ChildStoppedExact child terminal observationReuse internally; do not add template-specific WorkerStopped.
ShutdownChild, ChildShutdownRejected, ShutdownRequestedExact child drain request/rejection and actor shutdown ingressReuse internally where their current facts are complete. Deadline retirement remains ActorDrainPolicy.
ScheduleAfter, TimerElapsed, TimerId, TimerGenerationInterpreter-clock delay and exact timer correlationReuse internally. IDs are actor-owned and never builder inputs.
ReportToParentStructural lowering of a child reportKeep private to actor/interpreter integration. A worker user writes assignment.complete(result), never this type.
DeliveryRoutePreserve a statically selected logical or exact destination; constrain its associated protocol address to the owner where neededReuse for lifecycle/customer routes; do not force every actor to support a mixed route.

None of these rows proves that every current helper trait around the value must survive. SendEffects, SendsFor, InterpretSends, InterpretDelivery, InterpretChildDelivery, InterpretChildInput, and InterpretRequest are implementation machinery to audit as one interpreter equation. Keep only the smallest closed set used by the actual named effect product. Do not mirror it with template-local traits.

Required interpreter-contract replacement

The current InterpretSends contract returns one Interpreter::Error and documents that later lanes remain unconsumed after failure. That is incompatible with the selected ownership law: the source fold has already committed, so every later value still needs a surviving owner.

The replacement must interpret the named effect product into the equally named, ordered per-item settlement product from the solution. Every item is Accepted, Rejected, or NotAttempted after an exact dependency failure. Independent later items are interpreted; dependent later items are returned untouched. All current same-action occurrence-dependent operations must be grouped with their creation prerequisite: ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild. The staged sum distinguishes direct dependence on creation from dependence on required-observation acceptance. All required observations are attempted in named order; if several reject, their rejections remain independently owned and later dependent effects cite the first rejection's correlation. No lane index, path, lookup table, or general graph is authorized. ReturnsToEmitter/NoReturnToEmitter cannot be the general answer because the emitter may stop in the same action. They are replaced or narrowed to the live-primary-admission optimization only after typed host settlement is proven. The Driver gives the transitive settlement chain priority before the source's next ordinary user communication, so unresolved batches do not accumulate across separate user turns. This supplies no decreasing measure: the iterative queue alone proves neither bounded memory, termination, fairness, nor eventual return to ordinary traffic.

C. Conditional machinery, not selected core

Current familyKeep only if
EstablishedChildA focused use proves that a combined local-route/exact-actor helper product removes real ownership plumbing beyond the retained EstablishedCreation fact.
ObserveEstablished, ShutdownEstablishedThe operation genuinely starts from a transferable exact capability rather than the owner's child namespace.
ReplyRoute, ReplyDelivery, ReplyDeliveriesOne real API accepts both logical and exact reply routes. Exact-only callers must not pay for a mixed sum.
EventIngress, InjectEvent, Here, Inside, EventLayer, SendLayerThe current closed wrapper/interpreter composition truly needs them. Ordinary actor and template APIs never expose positions or paths.
ChildRole, ChildOccurrence, ResolveChildOccurrence, ChildHead, ChildTail, Children, ChildChoiceA closed authored birth product needs exact structural occurrence. Runtime supervisor roles and pool workers are values, not one type per role.
ReportTerminalOutcomeA fold must publish a terminal override independently of its own Step::Stop.
Activate, Initialized, ActivePure one-time Behavior initialization. They do not prove asynchronous worker readiness.
operations::ReadinessIts existing fixed-dependency/version law is independently needed. It is not worker activation.
shutdown coordinators and wrappersAn application explicitly composes that outer lifecycle policy. They are not internal pieces of an atomic supervisor or pool.

C.1 Complete disposition of current public core families

This table closes the audit over the families currently re-exported by crates/behavior/src/lib.rs. It is a family-level disposition rather than a promise to preserve every helper name.

Current public familyAtomic-actor decision
Address, MailAddr, EndpointAddressKeep as protocol/interpreter identity support. Builders never accept raw addresses.
Protocol, MessageProtocolKeep nominal Protocol. Keep MessageProtocol only as an explicitly structural helper; it must not collapse two domain protocols merely because address/message shapes match.
Behavior, BehaviorActed, BehaviorAddr, BehaviorMessage, InitializationTurn, ActiveTurnKeep as the pure fold contract and truthful aliases/turn witnesses. Atomic actors implement this contract directly.
BehaviorLayer, BehaviorBase, initialize, delegate_transitionKeep for genuine transparent wrappers and initialization composition. Supervisors/pools do not use them as a behavioral decomposition.
Actions, Step, Stopped, Never, Become, Acted, AppendSendKeep the explicit transition result. Convenience aliases remain only while they preserve all three action legs and the exact verdict.
SendEffects, SendsFor, NoSends, SendLayer and generated named productsKeep only the product/append laws required by concrete behaviors. Ordinary atomic-actor source sees semantic lane names, never SendLayer nesting.
SendInterpreter, InterpretSends, InterpretDelivery, InterpretEstablishedDelivery, InterpretChildDelivery, InterpretChildInput, InterpretRequestReplace the success/one-error short-circuit equation with complete per-item settlement; retain only the static concrete dispatch pieces that realize it.
InterpreterRequest, InterpreterRequests, ReportToParent, Own, SendInputKeep interpreter-facing and hidden from ordinary users. ReportToParent must compose behind assignment.complete, not appear in worker code.
NoReturnToEmitter, ReturnsToEmitterRemove as a universal rejection law. A live emitter may be a primary consumer, but host settlement is the required surviving owner.
Recipient, EstablishedRecipient, Delivery, EstablishedDelivery, EstablishedActor, InterpretEstablishedKeep logical and exact capability families distinct. Atomic protocols preserve the concrete selected route.
CreateChild, CreationKind, CreationRejection, AllocationRejection, BirthMode, NoBirths, BirthsKeep staged fresh creation and its typed rejection. Do not create template-specific duplicates.
ChildRoute, ChildDelivery, ChildInput, ChildReport, EstablishedCreationKeep as exact creator/child carriers where their facts remain complete; never expose structural routing in ordinary actor DevX.
ChildChoice, role/occurrence/position traits, fold/mapping traits, Children, and birth protocol productsKeep the closed authored-child algebra for macros/interpreters and other templates. Atomic runtime roles are private values, not one public type-level role per member.
User, UserEvent, Ingress, EventIngress, ChildInputIngress, InjectEvent, EventLayer, ComposedEvent, Here, InsideKeep typed event composition for real wrappers/interpreters. Paths and nesting markers remain generated/internal to ordinary atomic-actor source.
LogicalHostRequirements, LogicalDeliveryProtocols, birth logical-host projectionsKeep static evidence for intentional logical routes, including requests that carry a logical recipient. Exact and creator-local routes add no logical-host obligation.
the #[behavior] owning macroKeep syntax generation for the same concrete algebra. Do not add supervisor/pool or completion macros until ordinary composition is proven impossible.

Behavior intentionally exposes no finite mailbox reducer. One-turn initialization and event transitions are the algebraic boundary; Bombay owns runtime sequencing. The unpublished testkit alone owns finite test sequencing through drive and reports DriveDisposition::{MailboxDrained, BehaviorStopped(Stopped)} without a semantic boolean.

D. Delete or replace with the legacy templates

These names encode the architecture being replaced or incomplete policy shapes. Widespread use does not make them core.

  • old Proxy, Supervisor, DynamicSupervisor, WorkerPool, and KeyedWorkerPool implementations and their aliases;
  • ChildTopology, FixedFleetOwnership, slot/fleet ownership state, and wrapper/path-specific WithParent forms;
  • SupervisionEvent, SupervisionSends, SupervisorSends, PoolSends, and products whose fields exist only because the old templates are nested;
  • WorkerCreationResolved, WorkerStopped, ReplacementRequested, ReplacementResolution, ReportWorkerCreationResolved, ReportWorkerStopped, and ReportProxyUnavailable in their legacy shapes;
  • the existing RestartConfiguration/RestartPolicy split if it permits contradictory or meaningless combinations;
  • the current RestartDenial if it cannot retain overlap, clock-order, activation, or forced-retirement reasons required by the catalogue; and
  • assignment/completion types that expose customer routes or require workers to echo correlation fields.

Deletion happens only after the five replacements have feature and interpreter witnesses and all callers are migrated. No compatibility layer keeps the old concepts alive under new names.

E. Core gaps exposed by the laws

Five requirements are not solved by the retained kernel:

  1. Authoritative installation and initialization settlement. The pure init fold must precede host commitment, but initialization Actions must follow commitment of an installed-but-not-ready incarnation. Their partial success cannot be rolled back. The interpreter needs distinct pre-commit init/host rejection and post-commit initialization-effect settlement.
  2. Incarnation activation. The selected semantic equation splits committed installation into an actor-retained exact incarnation and a one-shot activation permit. BeginActivation consumes the permit and concrete plan; exact resolved/cancelled/late facts settle readiness. Hydration/I/O remains outside Behavior. The retained algebra and interpreter do not yet realize this equation.
  3. Creation-scoped dependency lowering. One creation and the complete current set of same-action occurrence operations—ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild—must lower as one named staged bundle, with direct and after-required-observation alternatives. Independent effects stay outside. Existing Actions does not yet prove that grouping without structural paths or runtime lookup.
  4. Rejected delivery and terminal projection. The selected semantic equation projects ordered per-item settlement from each named effect-product lane. Every item is accepted, rejected, or not attempted after an exact dependency failure; several failures remain distinct. A not-attempted item references the one authoritative prerequisite settlement rather than cloning its payload. A statically known host owns settlement after source commit or termination and transfers unresolved values outward to a root runner. Current interpretation does not realize that equation, and a committed fold cannot be rolled back. Its root boundary needs total heterogeneous static lifts, duplicate-role provenance, compositional wrapper transfer, and wrapper-depth-independent compiler diagnostics.
  5. Residual root lifetime. Actor-side forced retirement may transfer an uncancellable activation or future late incarnation to the root. The run future must remain a live typed owner until those facts resolve and the exact incarnation drains; a finished error value is not an owner. The current runner has no such residual state.

These are foundational interpreter equations, not permission to add a broad “lifecycle engine,” callback, ambient query, or template-local interpreter trait. Their semantic ownership is selected; the smallest concrete association with the retained core still requires a focused end-to-end regression and compile/interpreter witness.

F. Visibility rule

An ordinary user of a supervisor or pool should normally see only:

  • the actor's builder and public command/outcome protocol;
  • their domain role/key/job/result/worker types;
  • selected recovery, actor-specific capacity bounds, shutdown, and diagnostic policies; and
  • logical or exact recipients they deliberately provide.

They must not see child routes, occurrence positions, interpreter requests, parent-report plumbing, effect-lane products, nonce/timer issuers, activation joins, completion correlations, or typestate proof markers. If Rust makes an internal proof type appear in diagnostics, that is an implementation problem to measure—not a semantic reason to promote the type into the public model.

Solution design for the atomic actor catalogue (engineering record)

This document follows and cross-references atomic-actor-features.md. The feature catalogue is the requirement source; this document may not silently weaken it.

The minimal existing-core decision is in atomic-actor-retained-core.md, the minimized state/type equations are in atomic-actor-type-inventory.md, and the independent DevX research cross-check is in atomic-actor-research-audit.md. The disposition of every other current actor template is recorded separately in atomic-actor-other-templates.md; those later repairs are not part of the five-actor implementation stage.

Status language

  • Design-covered means this document names the state, transition, effect, error, or test mechanism that satisfies the referenced requirement.
  • Open means the requirement is recorded but its complete public type, transition, effect, and interpreter path have not all been selected.
  • Implemented means production code and focused regressions exist.
  • Verified means independent models, exhaustive/property/fuzz coverage, interpreter witnesses, and repository gates pass.

No new supervisor or pool production implementation exists. Several rows are still open after the research/DevX audit; the coverage matrix must not present them as design-covered. Nothing in this document may be reported as implemented or verified yet.

Coverage is dependency-closed: a row is Open whenever its observable transition depends on an open shared law, even if its local state transition is otherwise specified. A row may be Design-covered only when its own law and every foundational law it invokes are design-covered.

Open design blockers

Production work is blocked until these are resolved with public types and focused regressions:

  1. an interpreter witness for pure initialization, authoritative installed-but-not-ready host commit, partial initialization-effect settlement, and post-commit drain in that exact order;
  2. compile/interpreter realization of the selected activation permit/request/fact capability plus owner authorization and bounded occupied-ticket states, without moving hydration or I/O into Behavior;
  3. compile/interpreter realization of action settlement and delivery-rejection ownership for every lifecycle, management, customer, parent-report, and diagnostic route, including turn-local settlement priority and creation-scoped dependency bundles; the prototype must preserve the explicitly unbounded transitive-chain limitation rather than claiming termination or fairness;
  4. interpreter realization of the selected WaitForActorGraph versus RetireActorGraphAfter { deadline } actor-drain policy, exact forced-retirement fact, and live root residual state for uncancellable work;
  5. a compile-proven total terminal lift across heterogeneous children, duplicate roles, and wrapper orders, with a semantic root sum and bounded diagnostics;
  6. a compile-proven ordinary syntax that does not expose parent paths, reply aliases, repeated turbofish, or 64 public support names; and
  7. end-to-end interpreter witnesses for readiness and rejected deliveries.

The opaque pool completion token, customer-route ownership, separate stale diagnostic lane, canonical builder order, common-protocol heterogeneous fleet limit, dynamic durable-owner split, and precise FIFO rotation are selected local directions below. They are not implemented, and any matrix row that also depends on open settlement, activation, shutdown, or completion lowering remains Open.

Contradiction-closure ledger

This table is the cross-document authority for the latest specification review. Selected/Open realization means the semantic equation has one answer but its retained-core association, compiler proof, or interpreter witness is still missing; dependent coverage rows remain Open.

Review issueOne selected answerStatus and authority
Initialization versus installationRun the pure init fold first; establish and commit an installed-but-not-ready host before interpreting its initialization Actions; then settle those effects before activation. Post-commit rejection drains but never rewinds installation or prior effects.Selected/Open realization; Causal creation and activation policy, SH-READY, proxy/pool state equations
Rejected delivery after source stopOrdered per-item action settlement is owned by a statically known host and transfers outward if hosts stop. The live root retains residual ownership and returns a final value only after it settles. No emitter mailbox is required.Selected/Open realization; Action settlement and rejection ownership, SH-DELIVERY
Turn-local settlement priorityThe Driver processes settlement before the source's next ordinary user communication, so chains do not accumulate across separate user turns. No memory, termination, fairness, or eventual-return bound is claimed.Selected/Open realization; Action settlement and rejection ownership, SH-DELIVERY
Exact activation capabilityCommitted installation yields actor-retained exact incarnation plus one-shot installation permit; BeginActivation consumes that permit and the concrete plan. The owner separately records one bounded occupied authorization ticket, released by exact settlement or outcome.Selected/Open realization; Exact activation capability, SH-READY
Activation concurrency and late readinessEvery owner counts unresolved activation authorizations. Supervisors reserve conservatively at opaque proxy install; pools reserve at BeginActivation. Owners store waiting definitions or permits, exact occupied tickets, and an ordered authorization queue. Cancellation is logical after ownership transfer; late ready drains without publication.Selected/Open realization; SH-READY, actor state equations
Startup-limit meaningThe public law always bounds unresolved activation authorizations. Supervisor reservation is deliberately earlier and conservative because its proxy reports no progress; pool reservation occurs at direct activation emission.Selected; SH-READY, activation journeys and inventory
Dynamic cancellation ownershipTransaction-local preparation, proxy-create-emitted, waiting-for-authorization, install-emitted, awaiting atomic proxy outcome, ready, cancelling, and shutdown-owned phases are distinct. Worker installation and activation progress remain proxy-private. Only definition-owning phases return it.Selected/Open realization; Dynamic supervisor solution, DS-CANCEL
Diagnostic failure`Diagnostics[Route] = DeliverTo(Route)Terminate`; failed diagnostic delivery becomes terminal settlement and never sends recursively. Proxy uses its mandatory exact parent.
Readiness/query wordingRoutability begins only at exact Ready; dynamic public phase exposes only supervisor-observable reservation, proxy creation, activation authorization, awaiting-proxy-outcome, cancellation, drain, and retirement phases.Reconciled; SH-READY, DS-QUERY
Competing runtime state machinesThis solution is the sole normative ownership equation. The type inventory now references it and contains no duplicate private state tables.Reconciled; type inventory introduction and runtime references
Keyed submission modelSubmit { key, payload, reply_to } plus one concrete Fn(&Key) -> Role; no KeyedJob or SelectWorker.Selected; keyed solution, inventory, DevX
Key retirementThe transition committing permanent role unavailability automatically unbinds every retained binding for that role, releases capacity, and diagnoses exact generations. Temporary recovery retains bindings; irrecoverability is a cause, not a parallel terminal phase.Selected; KP-RETENTION
Pool ownership languageExactly one authoritative customer obligation/correlation, not one Rust value. Retry deliberately retains a canonical payload and dispatches a clone.Reconciled; Job ownership, FP-ASSIGN
Pool customer outcomesAdmission is `AcceptedRejected; terminal outcomes are exactly Completed
FIFO readiness orderingNo serviceable backlog may coexist with eligible idle capacity. Initial/replacement readiness, recovery, and completion commit directly to Busy with the oldest eligible queued job before Idle is possible.Selected; Pool member state, FP-TOPOLOGY, FP-ASSIGN
FIFO retry capacityBacklog capacity bounds new waiting admissions. Retry may add at most one formerly assigned job per role beyond that admission bound, preserving an absolute capacity + roster size queue bound and original admission order.Selected; Job ownership, FP-ADMIT, FP-INTERRUPT
Pool completion authorityEach dispatch issues affine worker-held authority plus pool-retained non-authorizing evidence, both bound to private worker-birth evidence. Completion matches the locked report's creator-local nonce plus that opaque evidence; the interpreter does not supply an exact incarnation capability.Selected/Open lowering; Job ownership, shared pool inventory
Rejected worker assignmentExact mailbox rejection consumes returned affine authority through typed reunion, reinserts the proven-unaccepted job by immutable admission ordinal, and quarantines the worker. Delivery settlement, completion, and worker stop form one exhaustive order-independent join.Selected/Open realization; Admission and dispatch, FP-ASSIGN
Pool initialization ownershipWhile worker initialization is unresolved, the lifecycle host owns its linear settlement and activation plan; pool state retains only exact initialization correlation until one result transfers the lawful next values.Reconciled/Open realization; Pool member state, AA-01 initialization law
Pool action applicationEvery action operation and settlement is a closed exact sum. Non-transactional apply returns applied prefix, rejected operation, and owned unattempted suffix; parent completion rejection returns the complete report instead of being discarded.Selected/Open runtime boundary; FIFO pool effects, action settlement
Keyed admission completenessOne total match maps every member state to AssignableNow, BacklogAdmissible, or Unavailable; a separate total management projection maps targets to Bindable or Unavailable. Pre-ready drain uses its stored recover-or-retire disposition in both.Selected; Keyed pool solution, KP-AFFINITY, KP-REBALANCE
Dynamic lifecycle ownerOne mandatory durable route is selected on the builder; request routes are temporary and cannot transfer lifecycle ownership.Selected; dynamic construction, DS-START
Forced-retirement terminationDeadline retirement atomically transfers exact outstanding ownership to the surviving host and records RetiredForced; that member is actor-side drained while late facts settle with the host.Selected/Open realization; Shutdown representation for owners, SH-SHUTDOWN
Drain terminology and scopeThe sole public sum is `ActorDrainPolicy = WaitForActorGraphRetireActorGraphAfter { deadline }`. It governs actor-graph retirement only; residual-root settlement and process exit are separate.
Root residual lifetimeForced actor-graph retirement moves the still-live root run future to ActorGraphDrained { residual }; no final error/result exists until late activation and exact drain ownership settle.Selected/Open realization; Action settlement and rejection ownership, Shutdown representation for owners
Terminal settlement loweringOne concrete root terminal sum receives total provenance-preserving static lifts from every heterogeneous child/wrapper sum. Duplicate roles never identify origin; outward lifts compose; wrapper-depth diagnostics must remain bounded.Selected/Open realization; Static terminal-projection equation, type inventory
Settlement dependency representationA closed staged bundle covers every current same-action occurrence operation: creation-result observation, exact established-creation observation, child-termination observation, child delivery, child input, and child shutdown. It selects direct-after-creation or after-required-observation ordering; rejection returns downstream values NotAttempted.Selected/Open realization; Creation-scoped dependency equation, retained-core prototype
Coverage matrixCounts are mechanically derived and open dependencies propagate to every observable row.Reconciled; Coverage matrix
Public DevXAll previous aspirational snippets are withdrawn. Five complete examples plus completion/wrapper proof are required before syntax is selected.Open; atomic-actor-devx.md
Other templates and Entity/MnesisOther template dispositions are a separate staged audit. Entity hosting, family drain, Mnesis hydration, and durable completion remain outside this five-actor stage.Explicit scope boundary; other-template and research-audit documents

System boundary

Five independent concrete folds are built in this order:

  1. Proxy<Worker>;
  2. FixedSupervisor<Role, Worker, ...>;
  3. DynamicSupervisor<Key, Worker, ...>;
  4. FifoPool<Role, Job, Result, Worker, ...>; and
  5. KeyedPool<Role, Key, Job, Result, Worker, Selector, ...>.

The names above describe intended semantic families, not final generic spelling. No shared runtime ownership engine is introduced during these five implementations. Configuration values may be shared because they are the same policy values; mutable lifecycle state and transition code are not shared until independent folds prove one smaller lawful extraction.

Every fold returns one named send product, one closed child-creation product, and one exhaustive next verdict. There are no lifecycle flags, parallel Option fields encoding a join, or boolean transition results. A predicate may be calculated transiently, but stored and returned semantic state is always a sum type.

Causal creation and activation policy

The central design decision is causal two-stage activation.

owner creates empty stable proxy
    -> runtime commits or rejects proxy creation
    -> only after commit, owner sends InstallInitial(worker)
    -> proxy stages fresh worker birth
    -> runtime runs the worker's pure init fold
    -> runtime establishes exact host ownership and commits the
       installed-but-not-ready incarnation
    -> runtime interprets and settles initialization Actions
    -> partial initialization failure drains; success issues activation permit
    -> installed worker enters its selected activation mode
    -> exact ready/rejected/stopped/shutdown fact resolves activation
    -> proxy returns one atomic readiness outcome

This is a deliberate Bombay policy, not an actor-model guarantee. It solves a major source of correlated flags:

  • worker creation cannot be reported before stable proxy creation commits;
  • the owner retains the worker definition until a proxy capability exists;
  • stable creation rejection cannot coexist with a legitimate worker report;
  • Started always contains the exact stable proxy capability. The proxy keeps the routable worker recipient private; any owner-visible worker incarnation value is opaque non-routable correlation evidence and is not published in Started or Restarted.

Pools have no proxy. They create workers directly, then apply the same installation-versus-readiness distinction in their own fold. They do not share the proxy's runtime state or transition implementation.

The runtime may still deliver a worker stop before the proxy receives matching installation or readiness resolution. Those joins remain inside the proxy, which owns all exact correlations. The proxy eventually emits one atomic parent outcome:

Ready(incarnation)
ActivationStartRejected(incarnation, complete unaccepted request,
                        terminal-or-forced drain fact)
ActivationRejected(incarnation, complete rejection,
                   terminal-or-forced drain fact)
InitializationFoldRejected(attempt, complete error)
InstallationRejected(attempt, complete host rejection and prepared init)
InitializationEffectsRejected(incarnation, failure classification,
                              terminal-or-forced drain fact)
StoppedBeforeReady(incarnation, complete stop fact)
Contradiction(complete conflicting facts)

Owners therefore never reconstruct readiness from separate creation, activation, and stop reports. The semantic activation request/fact capability is selected below; its association with the retained core and interpreter is still an open implementation design. Committed creation alone is not an implementation of this law.

H41b later corrected the custody split: Bombay retains the complete concrete initialization settlement in the worker environment and transfers it through runtime retirement. The proxy outcome above carries only the closed failure classification. The normative contract is atomic-runtime-settlement.md.

The capability boundary is explicit:

StableProxyCapability = externally routable service recipient
WorkerRecipient = proxy-private routable child capability
WorkerIncarnationEvidence = opaque non-routable lifecycle correlation

The proxy's internal installed-incarnation product owns both WorkerRecipient and WorkerIncarnationEvidence. Atomic parent outcomes project only the evidence. Fixed and dynamic supervisors retain that evidence for exact replaces and stop correlation, but their status, capability, Started, and Restarted values expose only StableProxyCapability.

Exact activation capability

The semantic capability is selected even though its final Rust integration is not compile-proven:

CommittedInstallation<Plan> {
    incarnation: InstalledIncarnation,
    initialization: InitializationSettlement,
    activation_plan: Plan,
}

InitializationResolved<Plan> =
    Initialized {
        incarnation,
        activation_permit: ActivationPermit,
        activation_plan: Plan,
    }
  | EffectsRejected { incarnation, settlement }
  | Stopped { incarnation, stop_fact }

BeginActivation<Plan> {
    attempt: ActivationAttempt,
    permit: ActivationPermit,
    plan: Plan,
}

ActivationResolved<Rejection> =
    Ready { attempt }
  | Rejected { attempt, rejection }

CancelActivation { attempt }

The creation request owns the concrete activation plan alongside the worker definition. On committed installation the interpreter returns that same plan with the exact incarnation and initialization settlement; it never clones, reconstructs, or looks it up. InstalledIncarnation is exact and closed to public traffic. ActivationPermit is the distinct one-shot capability tied to that committed installation. The emitted request consumes the permit and plan. Concurrency authorization is not a second capability: the owning supervisor or pool represents it by moving the member from its waiting sum variant into an exact occupied-ticket entry in the same commit that emits the install or activation request. The actor stores the incarnation and attempt; no linear value is owned by both state and Actions.

The exact order is normative:

pure init fold
  -> establish provisional/exact host ownership
  -> commit InstalledIncarnation, still closed to mailbox/user traffic
  -> interpret initialization Actions
  -> discharge their complete settlement
  -> issue ActivationPermit, drain, or record stop

An init-fold error occurs before host commit and executes no initialization effect. Host/allocation rejection returns the prepared post-init behavior and uninterpreted initialization Actions to settlement; it also executes no initialization effect. Once installation commits, earlier initialization effects are authoritative. A later initialization-effect rejection produces EffectsRejected and drains that exact installed incarnation without issuing an activation permit; it never reclassifies installation as rejected. An initialization Step::Stop similarly reports StoppedBeforeReady after all required initialization effects settle. BeginActivation never initializes the behavior again. An immediate plan may resolve Ready; a reported plan runs its concrete asynchronous future outside the fold. Both remain statically dispatched.

Each fixed supervisor, dynamic supervisor, FIFO pool, and keyed pool owns an activation-authorization limit and never owns more than that positive number of unresolved authorization tickets. Authorization always means the owner has allowed a worker to progress toward Ready. A supervisor reserves conservatively with the opaque proxy install input because it receives no worker-progress facts; a direct pool reserves with BeginActivation after initialization settlement. A proxy's local state has a structural limit of one. Definitions waiting for authorization remain in owner state. An occupied ticket is released only by its exact action settlement or terminal outcome.

CancelActivation is logical. If external work cannot be cancelled, the activation interpreter retains it but closes publication irrevocably. Late Ready becomes ReadyAfterCancellation and transfers the exact incarnation to drain; late rejection becomes RejectedAfterCancellation. If the actor has already terminated or been forcibly retired, its lifecycle host—not its mailbox—owns the unresolved activation record, including the exact incarnation needed to settle or drain that late result.

Action settlement and rejection ownership

The source actor is never the universal owner of delivery rejection. Before interpreting any action, the runtime creates one typed settlement record for every item in the complete named effect product:

ItemSettlement<AcceptedFact, Rejection> =
    Accepted { item, fact: AcceptedFact }
  | Rejected { item, rejection: Rejection }
  | NotAttempted { item, value, blocked_by: SettlementItem }

ActionSettlement<NamedLanes> {
    each semantic lane: ordered settlements for every emitted item
}

Each lane's Rejection is a closed sum projected from that lane's concrete effect type. It owns the complete payload, route kind, and exact reason. NotAttempted is required when a declared prerequisite—for example a same-action child creation—rejects. It returns the untouched dependent value and refers to the one authoritative prerequisite settlement by an opaque, non-reused item correlation. It does not clone or duplicate the prerequisite's owned rejection into every dependent item. Independent later lanes are still interpreted. Thus every emitted item has one settlement, several failures in one action are all preserved, and a short-circuit cannot silently discard a later value. For creation dependencies, SettlementItem is exactly the bundle-scoped correlation of the rejected prerequisite defined below: the creation settlement, or the first rejected required observation in named interpretation order. It is not a general item ID, lane index, structural position, or lookup key.

The complete named settlement product is retained by the actor's lifecycle host and outlives both the transition and actor. A continuing actor may be the primary consumer of rejection facts in lane order, but settlement transfers ownership of each fact to its mailbox only after admission succeeds. The host retains all remaining items. If the actor is stopping, has stopped, rejects a fact, or stops while processing an earlier fact, the lifecycle host remains the owner of every unadmitted item.

Settlement has a mandatory turn-local priority order. Before the Driver admits the source actor's next ordinary User communication, it processes every item in the current action batch in lane order by doing exactly one of:

admit the typed settlement fact on the source's system lane
or
transfer the item to the source's surviving host settlement

Actions produced while folding an admitted settlement fact create a new batch processed by the same priority rule before ordinary source traffic resumes. This is a per-source/host-chain priority rule, not a global scheduling barrier. It proves only that unresolved settlement does not accumulate across separate ordinary user turns: the next such turn is not admitted until the transitive settlement chain quiesces or ownership transfers outward.

This is not a decreasing measure or a bound on the transitive chain. A settlement handler may emit actions whose handlers emit more actions; that can consume unbounded time or memory and can starve ordinary traffic. An iterative Driver queue prevents call-stack growth only—it does not prove queue bounds, termination, fairness, or eventual return to user messages. A stronger claim requires a future typed transfer/budget policy and its own progress proof.

Installation establishes this ownership recursively and statically. A child host's unresolved settlement transfers into its parent's typed host settlement when the parent actor cannot consume it. If that parent also stops, the value continues outward without reinterpretation. The root application runner is the terminal live owner. It does not turn unresolved ownership into a finished error value. Its internal run state is:

Running
ActorGraphDrained {
    actor_summary,
    residual: NonEmptyResidualSettlement,
}
Settled {
    actor_summary,
    terminal_settlement,
}

NonEmptyResidualSettlement owns the concrete external activation tasks, their exact correlations, any incarnation produced by a late ready fact, and the capability needed to drain that incarnation. It is affine runtime state, represented by a closed statically dispatched product/sum—not an erased boxed future, cloneable report, registry, or actor mailbox. The root run future remains alive in ActorGraphDrained and consumes late facts until it can transition to Settled; only then may it return the final result to its caller. An API may publish the actor-side forced summary separately, but that observation is not the final application result and transfers no residual ownership.

There is no global settlement registry, lookup, logging fallback, or emitter mailbox that must remain alive forever. A host may apply only the lane-specific recovery named below; otherwise outward transfer to the still-live root is the terminal disposition. RetireActorGraphAfter therefore bounds actor-graph retirement, not completion of external work that the interpreter cannot cancel. A future bounded-process-exit policy would need an explicit typed emergency-abandonment outcome; it is not silently implied by RetireActorGraphAfter or Drop.

The internal host product may be topology-derived, but that structural type is not the ordinary root error. Each actor/template projects terminal settlement into one named semantic TerminalSettlement sum at its hosting boundary; lane variants own the exact rejected values and carry a semantic role as a value when needed. There is no generated variant per topology position and no exposed ChildChoice, SendLayer, Inside, or occurrence path. The root runner returns only the root's named projection (normally inferred through the run method). A compile-pass/fail and diagnostic-size prototype must prove that an ordinary application neither names nor receives the recursive host product; until then the public root error and every dependent DevX row remain Open.

Static terminal-projection equation

TerminalSettlement is not a universal erased envelope. For one concrete root terminal sum R, hosting constructs a closed family of statically dispatched lifts:

lift_own:   OwnTerminal -> R
lift_child_i: (ExactOrigin_i, ChildTerminal_i) -> R
lift_wrapper_j: WrapperTerminal_j<InnerTerminal> -> R

The family must satisfy all of these laws:

  1. Total heterogeneous lifting. Every variant of every concrete child or wrapper terminal sum maps to exactly one variant of R; no common erased payload, Any, trait object, serialization, or catch-all variant exists.
  2. Exact provenance preservation. Each lift consumes the exact source occurrence/capability, incarnation or generation, semantic lane, and owned rejection. R may carry a semantic role as a value, but a duplicate role value never substitutes for exact source provenance.
  3. Compositional outward transfer. Passing through hosts is function composition: lift_A_to_C = lift_B_to_C ∘ lift_A_to_B. A wrapper may lift its own terminal variants, but it cannot inspect, discard, duplicate, reorder, or reinterpret an inner terminal variant. A terminal-transparent wrapper changes only the inferred private lift composition. A wrapper with a genuinely new terminal law requires a semantic variant in R, never a structural-position variant or caller-authored path.
  4. Closed duplicate-role handling. Two children with equal semantic role values retain different exact origins internally. Their lifts may target the same domain variant only when that variant stores the distinguishing exact provenance; equality of role values is never the injection key.
  5. Bounded diagnostics. Compile fixtures at one, two, and eight repetitions of a terminal-transparent wrapper must expose the same root semantic type and primary error. Diagnostics must contain none of the private structural product/path names, and their recorded rendered-size budget may not grow with wrapper depth.

The Rust mechanism that supplies these lifts is deliberately unselected. A user-written callback or alias per child would violate the no-plumbing law; automatic structural projection could reproduce the original type explosion. The prototype must prove one inferred concrete mechanism through two heterogeneous children, duplicate role values, and two wrapper orders before TerminalSettlement becomes an authorized public name.

Creation-scoped dependency equation

Settlement does not use a general runtime dependency graph. The selected cross-lane dependency is any current occurrence-dependent operation authored against a child created in the same action. The closed current set is ObserveCreation, ObserveEstablishedCreation, ObserveChild, ChildDelivery, ChildInput, and ShutdownChild. Lowering groups them structurally at authorship time:

CreationBundle<CreateRequest, AfterCreation> {
    creation: CreateRequest,
    after_creation: AfterCreation,
}

AfterCreation =
    Direct(OccurrenceEffects)
  | AfterRequiredObservation {
        required: RequiredObservations {
            creation_observations,
            established_creation_observations,
            child_termination_observations,
        },
        then: OccurrenceEffects,
    }

OccurrenceEffects {
    child_deliveries,
    child_inputs,
    child_shutdowns,
}

LoweredAction<Independent, Creations> {
    independent: Independent,
    creations: closed heterogeneous product of CreationBundle values,
}

Each dependent value is physically owned by the same bundle as its one creation prerequisite; it does not name a lane index, wrapper path, runtime role, or registry key. The interpreter handles one bundle as follows:

creation accepted(exact binding), Direct(effects)
    -> interpret every occurrence-dependent effect against that binding
       in named lane order

creation accepted(exact binding), AfterRequiredObservation { required, then }
    -> interpret every required observation against that binding in this
       named order:
       1. creation_observations, in item order
       2. established_creation_observations, in item order
       3. child_termination_observations, in item order
    -> preserve the authoritative settlement of every accepted and rejected
       observation; one rejection never suppresses another observation
    -> if all required observations settle accepted,
       interpret every occurrence-dependent effect in `then`

one or more required observations rejected
    -> retain every authoritative observation settlement independently
    -> select the first rejected observation in the named order above as the
       deterministic blocking prerequisite
    -> return every dependent delivery, input, and shutdown untouched as
       NotAttempted {
           value,
           blocked_by: bundle-scoped correlation of that first rejection,
       }

creation rejected(rejection)
    -> retain the one authoritative creation settlement
    -> return every observation, delivery, input, and shutdown item as
       NotAttempted {
           value,
           blocked_by: bundle-scoped creation-settlement correlation,
       }

Each bundle-scoped correlation is created while producing the corresponding creation or observation settlement and is copied only as non-authoritative correlation. When several required observations reject, every rejection keeps its own correlation and owned value; only the first correlation in named interpretation order is copied into downstream NotAttempted settlements. Resolving it requires no lookup because the enclosing staged settlement owns the prerequisite and all dependents together. Independent effects remain outside the bundle and are still interpreted. Multiple child creations are a closed heterogeneous product of independent bundles, not a map. Direct encodes creation → occurrence effects; AfterRequiredObservation encodes creation → required observations → occurrence effects. A future occurrence-dependent operation must be added to this closed product and its settlement tests before it can lawfully appear in the same action; there is no catch-all request and no general DAG API.

The completeness boundary is explicit. Ordinary logical delivery is independent of a creator-local occurrence. ObserveEstablishedCreation is inside the bundle because it is authored from the pre-commit ChildRoute and returns the exact established capability only after creation commits. EstablishedDelivery, ObserveEstablished, and ShutdownEstablished are different: they require that resulting established capability as their input, so they cannot lawfully be authored in the original creation action. ChildReport originates at the child rather than the creating actor. Thus the six families above exhaust the current operations that can consume the pre-commit occurrence in the same creating action; adding another such family reopens this equation.

Fresh allocation is the actor-model law. Using a creator-local route to stage an exact-capability observation after commit is Bombay's derived construction. Requiring that observation for stable proxies, interpreting the three required observation lanes in the named order above, and selecting the first rejection as the downstream blocking correlation are deliberate Bombay policy choices; they are not guarantees supplied by the actor model.

The retained Actions surface does not yet expose this grouping. A focused core prototype must prove either a truthful lowering from existing named products or the smallest required interpreter-facing product change. Until it does, NotAttempted and every same-action dependent-effect row remain Open; adding handwritten paths or a runtime dependency registry is not an allowed fallback.

The required lane ownership is:

LanePrimary recovery while source livesSurviving owner
proxy → worker commandproxy, which may report unavailable without replaying implicitlyproxy lifecycle host
owner → proxy install/replacefixed/dynamic supervisor operation statesupervisor lifecycle host
pool → worker assignmentpool active job statepool lifecycle host with complete customer obligation
fresh proxy/worker creation and creation observationowning proxy/supervisor/pool pending-creation stateowning actor lifecycle host
activation begin/cancelowning actor activation stateowning actor lifecycle host with exact unresolved activation record
child shutdown/observation requestowning proxy/supervisor/pool drain stateowning actor lifecycle host
restart/deadline scheduling requestowning recovery/drain stateowning actor lifecycle host
parent reportnone after source commit; no implicit replayreporting child's lifecycle host terminal settlement
management replynone after source commit; no implicit replaydynamic-supervisor host terminal settlement
lifecycle eventnone after source commit; no implicit replaysupervisor host terminal settlement
customer outcomenone after active correlation removal; no implicit replaypool host terminal settlement with complete outcome
finalization/task/terminal/shutdown reportnone; the source may stop in the same actionsource lifecycle host directly
operational diagnosticpolicy belowlifecycle host directly

This settlement is a foundational interpreter contract, not an actor delivery, callback, global registry, or retry engine. Its precise association with the current Behavior/Actions types and child lifecycle facts must be proven by the focused core prototype before any dependent actor row can be implemented. It does not add a fourth behavior effect: Actions still contains the explicit communications and creations, and settlement is their typed interpretation result.

Diagnostic policy

Every configurable diagnostic-producing actor selects one semantic sum:

Diagnostics[Route] = DeliverTo(Route) | Terminate

That notation is the domain equation, not the selected Rust representation. A generic enum would leave Route unconstrained for Terminate and violate the no-placeholder law. The compile prototype must instead produce an inferred route-bearing builder state for delivery and an inferred route-free state for termination, with one exhaustive internal transition law. It may not solve inference with a default generic, public marker argument, or dummy route.

DeliverTo makes one attempt. Rejection immediately produces terminal UndeliverableDiagnostic { diagnostic, reason } in action settlement; it does not send a diagnostic about the diagnostic. Terminate skips delivery and emits the original diagnostic through a named terminal-settlement interpreter request in Actions while selecting Step::Stop in that same turn. The interpreter settles that explicit request directly with the lifecycle host. This gives an autonomous actor a truthful construction without a dummy route or ambient side channel while keeping the exact value recoverable.

An owner-created proxy has a mandatory exact structural parent, so its diagnostic disposition is fixed to DeliverTo(parent) by construction rather than exposed as another builder axis. Rejection follows the same terminal, non-recursive settlement law.

Terminate stops the actor in the diagnostic-producing action after preserving its other required effects. A later UndeliverableDiagnostic rejection causes a still-live actor's admitted settlement fact to select Step::Stop; if that fact cannot be admitted, the host/root terminal disposition applies directly. A diagnostic policy therefore has no recursive send, hidden effect, or indefinite retained error state.

1. Stable worker proxy solution

Construction and protocol

Proxy<Worker> is created empty. Its public protocol is exactly the worker's public protocol, preserving stable service identity. Its owner has a private typed control protocol:

InstallInitial(Worker)
Replace(Worker)
Shutdown

The proxy reports to its established parent through one concrete report sum:

InitialInstallation(InstallationOutcome)
Replacement(ReplacementOutcome)
WorkerStopped(complete stop fact)
Unavailable(original sender, lifecycle phase, complete command)

Runtime state

Dormant

CreatingInitial {
    attempt,
}

CreatingInitialAfterStop {
    attempt,
    stop_fact,
}

InitializingInitial {
    incarnation,
    initialization_settlement,
    activation_plan,
}

InitializingInitialAfterStop {
    incarnation,
    initialization_settlement,
    activation_plan,
    stop_fact,
}

ActivatingInitial {
    incarnation,
    activation_attempt,
}

ActivatingInitialAfterStop {
    incarnation,
    activation_attempt,
    stop_fact,
}

Ready {
    incarnation,
}

EmptyInitial

EmptyAfter {
    last_incarnation,
}

StoppingForReplacement {
    current_incarnation,
    reserved_attempt,
    replacement_worker,
}

CreatingReplacement {
    attempt,
    replaces,
}

CreatingReplacementAfterStop {
    attempt,
    replaces,
    stop_fact,
}

InitializingReplacement {
    incarnation,
    replaces,
    initialization_settlement,
    activation_plan,
}

InitializingReplacementAfterStop {
    incarnation,
    replaces,
    initialization_settlement,
    activation_plan,
    stop_fact,
}

ActivatingReplacement {
    incarnation,
    replaces,
    activation_attempt,
}

ActivatingReplacementAfterStop {
    incarnation,
    replaces,
    activation_attempt,
    stop_fact,
}

DrainingCreation {
    attempt,
    creation_kind,
}

DrainingCreationAfterStop {
    attempt,
    creation_kind,
    stop_fact,
}

DrainingWorker {
    incarnation,
}

DrainingInitialization {
    incarnation,
    initialization_settlement,
    activation_plan,
}

DrainingActivation {
    incarnation,
    activation_attempt,
    cause: ActivationDrainCause,
}

ActivationDrainCause is a closed private sum containing the complete unaccepted BeginActivation request, accepted-plan rejection, logical cancellation, or shutdown provenance. It is not an optional rejection field; the final proxy outcome consumes exactly the variant that caused the drain.

EmptyInitial and EmptyAfter are distinct because replacement provenance is present only in the latter. No Option<incarnation> hides that distinction.

Transition rules

  • InstallInitial is accepted only in Dormant. Fresh nonce reservation and collision checking precede the creation action.
  • Command in Ready emits one exact child delivery. Every other live state emits one Unavailable report containing the untouched sender and payload.
  • Successful committed creation enters Initializing*, owning the exact installed incarnation and initialization settlement. Complete successful settlement yields the one-shot permit and enters Activating*; only an exact ready fact enters Ready. Immediate activation may collapse the activation request/resolution, but never the committed initialization phase.
  • Initialization-fold or host rejection executes no initialization action and returns the proxy to the appropriate empty state. Initialization-effect rejection after commit enters DrainingInitialization; it reports the distinct rejection only after the exact installed incarnation is terminally settled, and cannot become empty earlier. Activation rejection follows the same drain-before-outcome law through DrainingActivation.
  • Replace in Ready reserves the replacement nonce first, then emits one shutdown request and owns the replacement definition.
  • Replace in EmptyAfter stages the replacement immediately.
  • Replace elsewhere returns the submitted worker in a typed rejection.
  • A matching stop in Creating* moves to the corresponding AfterStop state and emits no premature parent result.
  • Matching installed creation from Creating*AfterStop enters the matching initialization/stop join and can emit only StoppedBeforeReady, never Ready, even if later initialization and activation facts succeed.
  • Rejected creation from an AfterStop state produces Contradiction with both authoritative facts.
  • Matching stop from Ready emits WorkerStopped and becomes EmptyAfter.
  • Matching stop from StoppingForReplacement emits the stop report, stages the already-reserved replacement, and moves to CreatingReplacement.
  • Any pre-readiness failure after installation commits first stores its complete cause and drains that incarnation. The proxy emits its one atomic parent outcome and becomes empty only when the exact terminal or forced transfer fact closes that drain. The owning supervisor's occupied authorization ticket therefore cannot be released on a merely intermediate failure fact.
  • Stale, duplicate, wrong-kind, and wrong-worker inputs preserve proxy state and emit one complete worker-specific diagnostic carrying the current proxy phase. The expected correlation remains solely in proxy state.
  • Shutdown maps every live state to its corresponding drain state. It never sends to an already observed-dead worker and never realizes a cancelled replacement definition.
  • A parent-report delivery rejection never rewinds these states. The complete rejected report goes directly to the proxy host's terminal settlement; the proxy does not recursively diagnose failure of its mandatory structural report.

Proxy effects

worker_deliveries
worker_creations
worker_creation_observations
worker_stop_observations
worker_shutdowns
parent_reports

The interpreter order is creations first by Actions, then observation requests, worker deliveries/shutdowns, and finally parent reports. Focused tests assert the complete product for every transition, including empty lanes.

2. Fixed supervisor solution

Construction

The earlier five-axis product was incomplete. The candidate construction proof must account for:

Factory        = Missing | Selected(factory)
Roles          = Empty | NonEmpty(ordered unique roles)
Activation     = Missing | Immediate | Reported(concrete activation contract)
ActivationAuthorizationLimit = Missing | MaximumUnresolved(positive bound)
Recovery       = Missing | Selected(policy)
Failure        = Missing | Selected(reaction)
ActorDrain     = Missing | Selected(ActorDrainPolicy)
Diagnostics    = Missing | DeliverTo(concrete route) | Terminate
Events         = NotPublished | Published(concrete delivery route)

Events is not a mandatory proof axis: an autonomous fleet builds in NotPublished without a dummy route. When selected, the concrete route kind is preserved and receives ready stable-proxy capabilities and lifecycle events, never worker recipients. A typed status query remains available independently. The exact minimal typestate and diagnostic-disposition types are open; this list is a semantic checklist, not permission to publish one marker type per line.

build checks duplicate roles and prepares every initial factory result before constructing the behavior. Infallible and fallible factories need distinct truthful construction forms. A heterogeneous worker sum is accepted only when all variants share one public protocol.

Member state

Declared { role, initial_worker }

CreatingProxy { role, initial_worker, proxy_attempt }

ProxyStoppedBeforeCreation {
    role,
    initial_worker,
    proxy_attempt,
    stop_fact,
}

WaitingForActivationAuthorization {
    role,
    proxy_route,
    proxy_capability,
    prepared_worker,
    operation_ticket,
}

InstallDispatched {
    role,
    proxy_route,
    proxy_capability,
    operation,
}

AwaitingProxyOutcome {
    role,
    proxy_route,
    proxy_capability,
    operation,
}

Online {
    role,
    proxy_route,
    proxy_capability,
    worker_evidence,
}

Empty {
    role,
    proxy_route,
    proxy_capability,
    last_worker_evidence,
}

AwaitingInitialThenReplace {
    role,
    exact pending initial proxy operation,
    recovery_ticket,
    prepared_replacement,
}

WaitingToRestart {
    role,
    proxy capability,
    prior_worker_evidence,
    recovery_ticket,
    prepared_replacement_and_operation_ticket,
}

ReplacementDispatched {
    role,
    proxy capability,
    prior_worker_evidence,
    recovery_ticket,
    operation_ticket,
}

AwaitingReplacementProxyOutcome {
    role,
    proxy capability,
    prior_worker_evidence,
    recovery_ticket,
    operation_ticket,
}

Stopping { role, exact proxy ownership }

Retired { role, terminal reason }

The proxy-creation join has only CreatingProxy and ProxyStoppedBeforeCreation. Installed plus prior stop retires the dead proxy; rejected plus prior stop returns both facts as a contradiction. Worker creation/readiness is not reconstructed in this actor because the proxy returns one atomic readiness outcome. The proxy's installed-but-activating states remain hidden here.

Proxy commit moves the retained initial definition to WaitingForActivationAuthorization. The supervisor owns one global bounded activation-admission state with an ordered waiting-role queue and an exact set of occupied operation IDs. Each initial ID is paired once with a private witness during proxy-reservation preparation before any initialization creation is emitted. Opaque pair identity makes collision unrepresentable; process-wide allocation failure is not a supervisor rejection. Reserving an activation slot and emitting the already-ticketed proxy install input are one commit. Mandatory settlement discharge resolves InstallDispatched before another ordinary input or proxy report: acceptance enters AwaitingProxyOutcome, while rejection returns the complete install input to recovery. The slot is released only by the matching proxy atomic outcome or forced ownership transfer during drain.

An initial outcome matches the exact proxy source and expected initial operation. A replacement outcome additionally matches its nested replaces WorkerIncarnationEvidence against the participant's exact retained prior evidence. The supervisor does not inject or require its recovery ticket in the proxy protocol; source, operation kind, and predecessor evidence are already a complete correlation.

For replacement, one fresh affine operation pair per selected participant is created during recovery preparation and stored with that participant's prepared replacement. The issuing transition consumes the stored ID; it never allocates one. Worker preparation, recovery/timer correlation, budget, and checked release remain the recoverable pre-commit failures. No operation ID can overwrite or reuse another pair.

Recovery decision

This proposal originally copied trigger classification, budget charge, release provenance, and an eight-way prerequisite product into the admitted recovery. H76 rejected that Rust representation without changing the semantic law. The normative current representation is owned by fixed-supervisor.md: the participant order is before_trigger / trigger / after_trigger; restart release stores only Ready, an unsettled schedule, or one awaited timer; participant readiness remains in its current subject; activation availability is derived at issue time. Values already consumed by admission remain only in their actual owner, never as recovery breadcrumbs.

Before admission:

  1. classify eligibility from the complete terminal outcome;
  2. select the complete ordered candidate set;
  3. reject any overlap with an existing recovery ticket;
  4. call every selected factory and retain every result locally;
  5. reserve one exact operation ticket for every prepared replacement;
  6. prune budget evidence using the event time;
  7. reject out-of-order time explicitly rather than discarding future evidence;
  8. validate the atomic budget charge;
  9. compute checked delay and reserve exact timer correlation; and
  10. commit admission membership, correlations, prepared ownership, and budget charge once.

Any failure before step 10 leaves every non-trigger member and the budget unchanged. Later participant delivery, readiness, and replacement realization may fail independently and are never rolled back as a batch. The trigger's authoritative stop is represented as Empty; the configured failure reaction then maps the topology to RetireMember or StopSupervisor drain.

Fixed supervisor effects

proxy_creations
proxy_creation_observations
proxy_stop_observations
proxy_install_inputs
proxy_replacement_inputs
proxy_shutdowns
restart_schedules
lifecycle_events
management_replies
terminal_diagnostics
delivery_rejections

The AA-10 oracle remains blocked on the interpreter-facing child-terminal settlement that must return an emitted install or replacement when a proxy terminates without its normal outcome. These effect names do not implement that transfer, and no fixed-supervisor row depending on it may be promoted until a locked-boundary witness exists.

3. Dynamic supervisor solution

Construction and public protocol

The builder has at least these mandatory choices:

UnexpectedExit = Missing | KeepEmpty | Retire
EntryLimit     = Missing | MaximumEntries(non-zero bound)
Activation     = Missing | Immediate | Reported(concrete activation contract)
ActivationAuthorizationLimit = Missing | MaximumUnresolved(positive bound)
ActorDrain     = Missing | Selected(ActorDrainPolicy)
Diagnostics    = Missing | DeliverTo(concrete route) | Terminate
Lifecycle      = Missing | DeliverTo(concrete durable route)

Its public messages are:

Start { key, worker, reply_to }
Stop { key, reply_to }
Replace { key, worker, reply_to }
Query { key, reply_to }
Cancel { operation, reply_to }

Each request contains only its request reply route. The builder's one durable lifecycle route owns every later event; start cannot select, transfer, or replace it.

Entry state

CreatingProxy { entry_generation, operation, worker, proxy_attempt }
WaitingForActivationAuthorization {
    entry_generation, operation, worker, proxy
}
InstallDispatched { entry_generation, operation, proxy, install_attempt }
AwaitingProxyOutcome { entry_generation, operation, proxy, install_attempt }
Ready { entry_generation, proxy, incarnation }
Empty { entry_generation, proxy, last_incarnation }
Stopping { entry_generation, proxy, stop_operation, shutdown_observation }
Replacing { entry_generation, proxy, prior_incarnation,
            phase: ReplacementPhase }
Cancelling { entry_generation, proxy_or_pending_proxy, operation,
             phase: CancellationPhase }
Draining { entry_generation, phase: DrainEntryPhase }
Retiring { entry_generation, exact_unresolved_ownership }

Start preparation is transaction-local: it reserves every correlation before committing CreatingProxy and the creation action together. There is no stored or public Reserved phase.

ReplacementPhase and CancellationPhase are closed private sums mirroring the ownership boundary above: definition local before input emission, proxy creation emitted, waiting for activation authorization with committed proxy and definition, install input emitted, awaiting atomic proxy outcome, ready, or shutdown-owned. Only the first three variants own a returnable worker definition. DrainEntryPhase owns any pending proxy creation, transferred install settlement, unresolved proxy outcome, exact proxy shutdown, and forced-retirement deadline.

The supervisor owns a bounded activation-admission set and an operation-order waiting queue. Reserving a slot and emitting install/replace are one commit. Mandatory settlement discharge moves InstallDispatched to AwaitingProxyOutcome before another ordinary command or proxy report. The proxy alone owns worker creation, initialization, activation, and their races; it publishes no progress facts and returns one atomic terminal outcome. That outcome releases the slot.

The table is keyed by a semantic Key; proxy nonces are generated and retained separately. Duplicate start and capacity rejection return the submitted worker. Started is emitted only from AwaitingProxyOutcome after the proxy's atomic Ready outcome and contains the retained exact proxy capability.

Retirement removes the entry after all exact facts resolve. Reusing the same key creates a fresh entry_generation, so old facts cannot affect the new entry. KeepEmpty consumes capacity. Accepted start/replacement operations carry separate cancellation tokens; cancellation is a total match over each operation phase, not a boolean on the entry.

Request reply routes are not retained in long-lived entry state after their reply action is emitted; rejection ownership moves to action settlement. The durable lifecycle route and diagnostic policy are supervisor-global builder state rather than duplicated per entry.

The public query projection is exhaustive but does not expose owned values: CreatingProxy | WaitingForActivationAuthorization | AwaitingProxyOutcome | Ready | Empty | Stopping | Replacing | Cancelling | Draining | Retiring; an absent key returns Unknown. It does not claim to distinguish worker installation from activation because the proxy protocol publishes no such progress facts. No public Option plus phase flags encodes this sum.

Stop is the single public command that drains and removes a ready or empty entry. There is no parallel retirement command; automatic retirement remains the distinct UnexpectedExit::Retire policy.

Stop, replace, query, unexpected exit, unavailability, and global shutdown are total matches over the entry sum. Commands rejected by the current state return every owned input. A shutdown state owns a drain sum per entry:

The Draining variant above is the one shutdown equation; there is no second informal AwaitingProxyCreation | StoppingProxy | Retired state list.

No management mutation is accepted after the global actor enters drain.

Dynamic supervisor effects

proxy_creations
proxy_creation_observations
proxy_stop_observations
proxy_install_inputs
proxy_replacement_inputs
proxy_shutdowns
management_replies
lifecycle_events
terminal_diagnostics
delivery_rejections

4. FIFO pool solution

Construction

The builder product is:

Factory       = Missing | Selected(factory)
Workers       = Empty | NonEmpty(ordered unique roles)
Activation    = Missing | Immediate | Reported(concrete activation contract)
ActivationAuthorizationLimit = Missing | MaximumUnresolved(positive bound)
Recovery      = Missing | Selected(policy)
Backlog       = Missing | Selected(capacity)
Interruption  = Missing | Fail | Retry
Distribution  = Missing | FIFO
ActorDrain    = Missing | Selected(ActorDrainPolicy)
Diagnostics   = Missing | DeliverTo(concrete route) | Terminate

Only the complete product builds. Retry and Fail both retain a job copy while it is assigned because the worker owns the dispatched message. Payload clone occurs before admission commit; the customer route never leaves the pool. The public behavior therefore states its required clone bounds honestly; if cloning unwinds, no pool state or Actions value has committed. This law does not promise to recover a caller value already moved into the fold during unwind.

Job ownership

QueuedJob {
    job_id,
    admission_ordinal,
    customer_route,
    retained_payload,
    origin: NeverAssigned
          | Retried { prior_role, interruption_classification },
}

AssignedJob {
    assignment_id,
    completion_correlation,
    worker_birth_evidence,
    job_id,
    customer_route,
    retained_payload,
    worker_role,
    worker_incarnation,
}

The FIFO backlog owns only QueuedJob. A busy member owns its single AssignedJob; there is no separate in-flight collection. A dispatch gives the worker an affine completion authority paired with the assigned record's non-authorizing completion_correlation. The worker cannot inspect or construct either value, and retained correlation cannot manufacture a result.

The invariant is one authoritative customer obligation and active completion correlation, not one physical Rust value. Under Retry, the pool retains the canonical retry payload while the worker owns a cloned execution payload; neither value independently authorizes a customer outcome.

The canonical pool protocol is:

Accepted { request, job }
Rejected { request, payload, reason }
Completed { job, role, result }
ReturnedQueued { job, payload, reason }
ReturnedAssigned { job, role, payload, reason }

Both admission variants echo the caller's opaque request correlation; Accepted also returns the distinct pool-issued job identity. The pool never trusts request correlation as internal identity or retains it in the accepted job: admission commit moves it into Accepted, while rejection moves it into Rejected. Accepted and Rejected are admission outcomes. The remaining three are the only terminal customer outcomes. No generic Returned variant exists: a role is known only after assignment. Rejection of any emitted outcome transfers that exact value to action settlement and cannot recreate an active job.

Pool member state

The pool creates workers directly. The stable pool actor retains the mapping from semantic role to each fresh worker incarnation; no stable proxy exists in this topology. Pool lifecycle rules use the same policy values as fixed supervision but are implemented directly in the pool fold. Its complete pre-ready ownership progression is:

Prepared { role, worker_definition }
Creating { role, creation_attempt }
Initializing {
    role, incarnation, initialization_attempt
}
WaitingForActivationAuthorization {
    role, incarnation, activation_permit, activation_plan
}
ActivationDispatched { role, incarnation, activation_attempt }
Activating { role, incarnation, activation_attempt }
DrainingPreReady {
    role, incarnation,
    cause: initialization rejection | activation-start rejection
           | accepted-plan rejection | cancellation | shutdown
    after_drain: ResumeRecovery(recovery decision) | Retire(terminal reason)
}

Recovering { role, exact decision, prepared worker or exact timer }
Stopping { role, exact outstanding worker ownership }
Retired { role, terminal reason }

The pool also owns one declaration-order activation waiting queue and an exact bounded set of occupied activation tickets. While initialization is unresolved, the lifecycle host owns the linear settlement and activation plan; actor state retains only initialization_attempt. Its exact result transfers the permit and plan into the waiting state. Reserving a ticket and emitting BeginActivation are one commit. Activation settlement, stop, and forced drain may arrive in either order; no synchronous interpreter guarantee is assumed. Rejected dispatch returns the complete request to recovery; exact ready, activation rejection, stop, or forced transfer releases the ticket once. None of these pre-ready states is eligible for job dispatch. A post-commit initialization or activation failure enters DrainingPreReady and cannot enter recovery or accept work until exact terminal or forced-transfer settlement. Ready worker states are split into:

Idle { worker route, private worker-birth evidence }
Busy {
    worker route,
    private worker-birth evidence,
    assigned_job,
    assignment_delivery_completion_stop_join,
}

Recovery states that originate from Busy own one interruption resolution:

ReturnFailure(assigned_job)
RequeueRetry(assigned_job)

The exhaustive assignment join orders delivery settlement, completion, and worker stop before it emits or requeues the selected alternative. No permanent returned-assignment tombstone is stored. A later result with that token becomes an operational stale diagnostic and cannot select a customer.

The pool maintains this invariant after every fold:

no serviceable queued job coexists with an eligible Idle member

Initial readiness, replacement readiness, recovery completion, and job completion all run the same oldest-eligible dequeue transition. If backlog is serviceable, the transition commits the worker directly to Busy and emits the assignment; it never commits an intermediate Idle. Only an empty or currently ineligible backlog permits Idle. FIFO assignment to a newly ready role advances the circular cursor exactly as an ordinary assignment to that role; readiness does not create a separate fairness rule.

Admission and dispatch

  1. Preserve the caller request correlation and classify shutdown, serviceability, idle availability, and full backlog before allocation.
  2. Reject full or unserviceable submission unchanged; otherwise reserve one fresh { job identity, admission ordinal } pair.
  3. Apply the maintained invariant: an eligible idle role implies there is no older serviceable backlog job; this is a state proof, not a runtime assert.
  4. Select the next ready idle role from the circular declaration-order cursor.
  5. If idle, reserve a fresh assignment/correlation-authority pair and clone the execution payload before commit; retain the canonical payload, customer obligation, and non-authorizing correlation, then commit Busy and emit one assignment carrying the affine authority.
  6. A job-pair or immediate-dispatch preparation failure rejects through its own typed branch and never falls back to queue admission.
  7. Otherwise move the original payload into the queue ordered by immutable admission ordinal.

Capacity is the new-admission waiting bound. A zero-capacity pool takes branch 4 or 6. Retry is not new admission: it may insert one formerly active job per role beyond that bound, so the complete queue remains bounded by capacity plus roster size. Queue-to-worker dispatch reserves its assignment/correlation-authority pair at dispatch time. Exhaustion or collision returns that accepted queue head through its exact ReturnedQueued or ReturnedAssigned provenance and continues the finite FIFO fill; it cannot strand a serviceable head beside an idle worker. Completion resolves the private authority, then validates the report's creator-local child nonce plus private worker-birth evidence before mutation. A match uses the pool-retained customer route, emits one customer result, advances the cursor, and either commits the member directly to Busy with the oldest eligible queued job or to Idle when none exists. A mismatch emits the complete result only on the separate diagnostic disposition and preserves active ownership.

Recovery and shutdown

Worker lifecycle uses the same policy values as fixed supervision but remains pool-owned transition code over direct worker children. A busy-worker stop first resolves its exact AssignedJob according to Fail or Retry, then begins recovery. Irrecoverable retirement redistributes general FIFO backlog to surviving workers; if no live or recoverable worker exists, all stranded jobs receive one terminal outcome. Retry reinserts the interrupted assignment by its immutable admission ordinal, preserving order even when several workers stop in a different order from their jobs' admission. The queue stores only prior role and semantic interruption classification; recovery alone owns the authoritative stop. Exact assignment-delivery rejection uses typed affine reunion before the same ordered reinsertion and is a safe pre-execution return. Delivery settlement, completion, and worker stop join in any order without a second job disposition.

Shutdown atomically extracts all queued and assigned jobs into customer outcomes, transfers their active completion joins, cancels delayed recovery, and drains every direct worker child. Later completions are stale diagnostics and emit no second customer outcome. ActorDrainPolicy explicitly chooses WaitForActorGraph or exact RetireActorGraphAfter retirement with forced facts.

FIFO pool effects

CreateWorker { reservation, submission }
ObserveWorkerCreation { reservation }
ObserveWorkerStop { child_nonce }
BeginWorkerActivation { child_nonce, attempt, permit, plan }
CancelWorkerActivation { child_nonce, attempt }
DeliverAssignment { child_nonce, assignment, command }
ShutdownWorker { child_nonce, correlation }
ScheduleRestart { recovery, timer, deadline }
ScheduleDrainDeadline { timer, deadline }
DeliverAdmission { route, outcome }
DeliverCustomerTerminal { route, outcome }
DeliverDiagnostic { route, diagnostic }
TransferTerminalDiagnostic { diagnostic }
TransferUnexpectedInput { input }
TransferDrainResidual { residual, cause }
ReportCompletionToParent { completion_evidence }

Each operation has its own accepted/rejected settlement carrying the complete request or outcome. Ordered non-transactional application returns an applied prefix, one exact rejected operation, and the closed owned unattempted suffix. The current runtime does not yet provide that result, and local parent report delivery discards closed-parent rejection; both remain explicit blockers.

5. Keyed pool solution

The keyed pool is a separate direct fold. It reuses configuration value types and assignment/outcome value types, not a nested FIFO pool behavior.

Its builder replaces Distribution = FIFO and global backlog with:

Distribution = Keyed(concrete selector)
Backlog      = PerRole(capacity)
Bindings     = Maximum(capacity)

Runtime binding state contains only retained entries:

Bound { key, generation, worker_role }

Absence is represented by no table entry. There is no persistent Unbound state, per-key counter, or tombstone. Each Bound entry is the sole pool owner of its retained key. Each accepted job stores only copyable, non-authorizing admitted-binding evidence { generation, worker_role }; it does not clone or own the key. Each role has its own bounded FIFO queue, so a busy selected role cannot consume another role's capacity or idle worker.

Rebalance validates an exact absence/generation expectation and the target's separate management eligibility, then changes only the binding table. It never walks or edits queued or assigned jobs. Unbind removes only future-admission affinity and releases binding capacity; a later admission or explicit unbound rebalance allocates a fresh opaque generation without retaining history for the absent key.

For admission, the current target member projects to exactly one of:

AssignableNow = Idle

BacklogAdmissible = Prepared
                  | Creating
                  | Initializing
                  | WaitingForActivationAuthorization
                  | ActivationDispatched
                  | Activating
                  | Busy
                  | Recovering
                  | DrainingPreReady { after_drain: ResumeRecovery }

Unavailable = Stopping
            | Retired
            | DrainingPreReady { after_drain: Retire }
            | any member after global shutdown owns it

This is a total match over the complete member sum. DrainingPreReady is not classified from its cause by guesswork: the fold has already retained one exhaustive after_drain disposition. There is no wildcard/default arm.

An admission-created binding is committed only with accepted work. AssignableNow dispatches immediately; BacklogAdmissible requires remaining capacity in that role's queue; Unavailable rejects. If the per-role capacity is zero and the target is not ready-idle, the job and proposed binding are both returned unchanged. This law distinguishes eventual service eligibility from immediate assignability without inferring readiness from a role or binding.

Management-created bindings obey a different total projection because they admit no job and consume no backlog capacity:

Bindable = Prepared
         | Creating
         | Initializing
         | WaitingForActivationAuthorization
         | ActivationDispatched
         | Activating
         | Idle
         | Busy
         | Recovering
         | DrainingPreReady { after_drain: ResumeRecovery }

Unavailable = Stopping
            | Retired
            | DrainingPreReady { after_drain: Retire }
            | any member after global shutdown owns it

Unknown role is a distinct typed rejection. Irrecoverable is not retained as another member variant: the irrecoverable decision commits a permanently unavailable drain or retired phase. Temporary Recovering and DrainingPreReady { ResumeRecovery } remain bindable and retain bindings.

Every management command carries one expectation:

BindingExpectation = Absent | Exact(BindingGeneration)

For an absent key, rebalance requires Absent, a bindable target, free binding capacity, and a freshly reserved generation; success moves the command key into the new binding without a job. Exact(_) is stale. Unbind with Absent returns the typed AlreadyUnbound outcome; unbind with Exact(_) is stale.

For a binding at exact generation g, both rebalance and unbind require Exact(g). Absent or another generation returns the complete command unchanged with actual = Exact(g). A rebalance to the same bindable role is an accepted no-op preserving g. A role-changing rebalance reserves fresh g2 before atomically moving the stored key into { g2, target }; failure preserves the old binding and returns the complete command. Exact unbind removes and returns the complete binding. Expectation comparison precedes target validation, so stale commands cannot inspect then mutate a later generation.

The per-role keyed queue obeys the same ready-time dequeue invariant as FIFO: a readiness or recovery transition for role R commits directly to Busy with R's oldest queued job when one exists. A new job for R cannot observe an idle member while an older serviceable job remains in that role's queue.

The transition committing permanent unavailability extracts and terminates that role's queued and assigned work once and atomically removes every retained binding to that role, releasing capacity and emitting exact key/generation diagnostics. Entering terminal pre-ready drain, terminal stopping, or retained Retired state cannot leave a binding behind. Retry returns work to its retained role while that role remains recoverable, and temporary recovery retains bindings. A later rebalance cannot revive returned work. Shutdown extracts every partition, deletes each returned active correlation after committing its single customer outcome, removes every binding, and drains the concrete direct-worker lifecycle owned by this fold. Late completions have no customer destination and follow the operational diagnostic disposition; no permanent tombstone is retained.

Shutdown representation for owners

Fixed supervisor transforms proxy ownership, while both pools transform direct worker ownership, into the same semantic drain alternatives:

AwaitingChildCreation {
    exact attempt,
    prior stop fact if it arrived first,
}

AwaitingChildActivation {
    exact incarnation and activation generation,
    prior stop or rejection fact if it arrived first,
}

StoppingChild {
    exact route and capability,
}

Retired {
    terminal fact or creation rejection,
}

RetiredForced {
    exact forced-retirement fact,
    host_transfer_receipt,
}

Pending recovery decisions move to:

CancelledTimer { exact timer identity and generation }

The retained replacement definitions are dropped as cancelled owned values; they are never created. Exact later timer arrival consumes CancelledTimer. Deadline retirement atomically transfers the complete outstanding ownership to the surviving lifecycle host and records its typed receipt in RetiredForced. That alternative is actor-side drained: exact late lifecycle, activation, creation, delivery-settlement, and timer facts belong to the host and cannot revive the actor. The actor selects Stop only when every drain member is Retired or RetiredForced and every accepted pool job is completed, returned, or included in an exact forced transfer.

If the surviving host is the application root, that transfer moves the root run future to ActorGraphDrained { residual }; it does not complete the future. A late ready fact is admitted to that residual state, the exact late incarnation is drained, and only complete settlement permits Settled and the final runner return.

WaitForActorGraph owns no deadline timer. RetireActorGraphAfter owns one exact deadline timer and can enter RetiredForced only from a still-outstanding alternative. If the interpreter rejects that deadline schedule, the rejecting settlement is itself the authoritative inability to enforce the configured bound. In the same settlement turn, every still-outstanding member transfers to the surviving host and enters RetiredForced with DeadlineScheduleRejected { request, reason } as its cause. This immediate forced transfer emits no accepted timer or child-stop fact and never falls back to WaitForActorGraph. Delivery rejection of a shutdown or final report never counts as a child terminal fact.

Error and outcome boundary

Expected domain rejection is a successful transition with a typed outcome and unchanged state. Examples: duplicate dynamic key, full backlog, stale completion, unavailable proxy, budget denial, invalid rebalance, and overlapping replacement.

Controlled behavior error is reserved for contradictory authoritative runtime facts or violated interpreter contracts that cannot be represented as an ordinary request rejection. Every such error owns the complete conflicting facts. Sequence exhaustion that occurs before an externally authoritative transition returns a typed domain rejection with the submitted owned value.

No production branch uses panic!, expect, unreachable!, a sentinel, or an empty collection as a semantic failure.

Coverage matrix

The range in each row covers every bullet currently present under that feature group in the feature catalogue. Counts are generated from the catalogue's top-level requirement bullets; a changed count invalidates this table. Open shared activation, settlement, completion-lowering, or drain realization is inherited by every row whose observable transition uses it.

Requirement rangeDesign mechanismStatus
SH-ACTOR-01..07Five direct folds and explicit Actions are selected; authoritative initialization/interpreter ordering remains openOpen
SH-STATIC-01..06Closed event/report sums, concrete generics, role/nonce/capability separationDesign-covered
SH-CREATE-01..08Fresh staged creates, provenance, and typed exhaustion selected; initialization and dependent-effect settlement remain openOpen
SH-READY-01..21Authoritative installation before initialization effects, exact activation request/fact, concurrency, logical cancellation, and late settlement; retained-core/interpreter realization absentOpen
SH-CORRELATE-01..07Exact correlation newtypes, prepare-before-commit, owned rejection values, named lanesDesign-covered
SH-DELIVERY-01..18Route preservation, turn-local settlement priority, live-root residual ownership, and semantic terminal projection selected; progress bounds and realization absentOpen
SH-DIAGNOSTIC-01..09`DeliverToTerminate`, outward transfer, and non-recursive failure selected; terminal-settlement realization absent
SH-SHUTDOWN-01..16Dedicated drain sums, host transfer, live residual root, and selected ActorDrainPolicy; deadline/interpreter witness absentOpen
PX-IDENTITY-01..05One stable proxy with one exhaustive incarnation stateDesign-covered
PX-INIT-01..08Empty proxy, private install, and local creation/initialization/stop join; initialization settlement remains openOpen
PX-ACTIVATE-01..10Installed/activating states and distinct initialization/start/activation outcomes; activation input remains openOpen
PX-ROUTE-01..05Ready-only delivery and complete unavailable report; activation and settlement inheritedOpen
PX-REPLACE-01..11Reserved nonce and provenance specified; activation and report settlement inheritedOpen
PX-STOP-01..04Exact stop matching and AfterStop joins; parent-report settlement inheritedOpen
PX-SHUTDOWN-01..09Creation/activation/worker drain; parent-report rejection remains openOpen
FS-BUILD-01..13Canonical semantic axes known; minimal activation/diagnostic typestate and syntax remain openOpen
FS-TOPOLOGY-01..11Ordered role/member sum, waiting authorization, and exact proxy route/capability ownership; activation realization absentOpen
FS-FACTS-01..07Atomic proxy outcomes specified; readiness and lifecycle settlement inheritedOpen
FS-OPERATE-01..06Status/capability snapshot and diagnostic disposition known; public protocol and settlement openOpen
FS-ELIGIBILITY-01..05Exhaustive Recovery policy match on complete terminal outcomeDesign-covered
FS-STRATEGY-01..08Immutable snapshot selection and ticketed unresolved participantsDesign-covered
FS-BUDGET-01..11Atomic charge, inclusive monotonic window, explicit out-of-order rejectionDesign-covered
FS-TIMING-01..10Checked delay values and exact eight-state readiness/timer/authorization join; activation realization absentOpen
FS-ATOMICITY-01..04Prepare all factories and policy calculations before one commitDesign-covered
FS-FAILURE-01..04Failure reaction sum selected; diagnostic settlement and drain realization inheritedOpen
FS-SHUTDOWN-01..08Owner-only drain is covered; deadline interpretation and rejected delivery inherit open shared lawsOpen
DS-BUILD-01..07Exit/capacity/activation/durable-route requirements known; minimal builder remains openOpen
DS-START-01..10Keyed reservation and configured durable owner selected; readiness and reply/lifecycle settlement remain openOpen
DS-QUERY-01..04Read-only exhaustive projection selected; management-reply settlement and public protocol remain openOpen
DS-STOP-01..05Capability-owning stop states specified; reply/shutdown settlement inheritedOpen
DS-REPLACE-01..08Stable proxy replacement and ready-only realization; activation path remains openOpen
DS-EXIT-01..06Empty/retain/retire sum; durable unavailability delivery remains openOpen
DS-RETENTION-01..06Bounded entries and generations selected; late-diagnostic settlement inheritedOpen
DS-CANCEL-01..08Phase-exact ownership and outcomes selected; transferred install/activation/settlement realization remains openOpen
DS-SHUTDOWN-01..06Global mutation closure; deadline retirement and route rejection inherit open shared lawsOpen
FP-BUILD-01..09Semantic axes known; minimal activation/diagnostic builder remains openOpen
FP-TOPOLOGY-01..12Direct pool-owned lifecycle, bounded authorization tickets, ready-time dequeue, and role preservationOpen
FP-ADMIT-01..11Authoritative obligation and atomic admission specified; reply/assignment settlement and completion lowering openOpen
FP-ASSIGN-01..09Opaque authority, exact rotation, and no-idle-with-backlog invariant specified; lowering and settlement openOpen
FP-COMPLETE-01..07Token/source match and stale lane selected; completion lowering and outcome/diagnostic settlement openOpen
FP-INTERRUPT-01..09At-least-once retry ownership specified; returned-outcome settlement inheritedOpen
FP-FAILURE-01..05Retired-member extraction specified; diagnostic/customer settlement inheritedOpen
FP-RETENTION-01..05Active-only correlation selected; safe late-result diagnostic settlement inheritedOpen
FP-SHUTDOWN-01..07Atomic extraction/direct drain; rejected outcomes and deadline retirement remain openOpen
KP-BUILD-01..07Explicit submitted key plus one concrete selector selected; minimal builder and activation/diagnostic syntax openOpen
KP-AFFINITY-01..09Total member-state admission projection, per-role ready dequeue, and atomic binding admission specified; settlement inheritedOpen
KP-REBALANCE-01..09Future-only rebalance/unbind specified; management reply settlement inheritedOpen
KP-END-01..05Role-retained completion/retry specified; completion lowering and customer settlement inheritedOpen
KP-RETENTION-01..06Automatic retirement unbind selected; exact diagnostic settlement inheritedOpen
API-01..15Canonical fluent goals recorded; compile/diagnostic evidence absentOpen
EFFECT-01..22Named products and complete current creation-scoped dependency equation selected; lowering and rejected-delivery interpreter paths absentOpen
VERIFY-01..17Required state, residual-root, terminal-lift, dependency, and repository gates enumerated; no replacement implementation existsOpen
NONFEATURE-01..10Explicit deletion list after replacement proofDesign-covered

Implementation acceptance rule

The next lawful stage is foundational prototype work, not implementation of the five actors. Its order is:

  1. initialization/authoritative-host ordering witness;
  2. complete creation-bundle lowering for every occurrence-dependent operation;
  3. per-item settlement, static terminal lifting, and residual-root ownership;
  4. exact activation permit/request/fact plus authorization tickets; and
  5. compiler-pass/fail builder and bounded-diagnostic prototypes.

Each prototype begins with its focused law regression and the smallest end-to-end interpreter witness. It may change production algebra only after the design-provenance ledger and change-containment threshold are recorded for that prototype. It may not simultaneously migrate actor templates.

Implementation of proxy, fixed supervisor, dynamic supervisor, FIFO pool, or keyed pool remains blocked until all five foundational prototypes compose. A row changes from design-covered to implemented only when its production symbols point back to those regressions. Legacy deletion begins only after all five templates are verified and migrated without compatibility wrappers.

Atomic actor verification contract (engineering record)

The campaign evidence in this record was last committed at 1f20cc4. Its feature-complete verdicts describe local gates at that revision. The current repository quality audit tracks later verification and downstream integration separately.

Status: normative verification owner. No family document duplicates this matrix; each links here and adds only family-specific law references.

Current campaign state

feature-complete means every currently named aggregate-local gate passes. It does not mean the whole campaign, Bombay integration, or the Bombay system is complete. active means production behavior exists but a named local gate is still open. The family law documents remain semantic oracles; they do not by themselves establish implementation status.

FamilyStateExecutable evidenceRemaining gate
StableProxyfeature-complete locallyindependent models, compile contracts, two stateful fuzz targetsfinal fresh audits and Bombay root custody
FixedSupervisorfeature-complete locallyfocused models, exact multi-role examples, four stateful fuzz targets, 34 worker-rejection cases, 30 source/corrupt/unattempted preparation-return cases, all 5,040 coordinated preparation/shutdown arrival orders, every distinct-role RestForOne overlap pair, 540 lawful three-recovery correlation traces, complete 753-candidate owner reconciliation, type-valid root/protocol inversions, exact lifecycle/management/event projections, and full aggregate-residue auditfinal fresh audits and Bombay custody
DynamicSupervisorfeature-complete locallyindependent models, compile contracts, three closed mutation partitions, and four stateful fuzz targetsfinal fresh audits and Bombay root custody
FifoPoolfeature-complete locallyindependent customer/recovery/retirement/queue models, mutation audit, performance workload, one stateful fuzz targetfinal fresh audits and Bombay custody
KeyedPoolfeature-complete locallytwo bounded independent models, shared customer law suite, two stateful fuzz targets, and complete 232-candidate owner reconciliation with all 72 executable mutations caught and 160 compiler-unviable substitutions retained only as inventoryfinal fresh audits and Bombay custody

The current fuzz manifest therefore contains thirteen replacement-family targets: two proxy, four fixed-supervisor, four dynamic-supervisor, one FIFO, and one binding-only plus one assignment/retirement keyed target. A prior combined keyed assignment/binding/retirement target was rejected because it mixed three independently testable responsibilities; its absence is not evidence that those gates passed.

Evidence order

  1. State the actor-model, derived, or Bombay policy law.
  2. Record the user syntax and complete observable transition.
  3. Add a focused compile or pure-fold regression in domain vocabulary that fails against the prior design for that law.
  4. Run deliberate inversion and show failure for the intended reason.
  5. Implement the smallest representation only after the law and interpreter path are coherent.
  6. Audit every production symbol against its pre-edit law and regression.

Compiler diagnostics can reject an encoding but cannot originate a type, trait, bound, callback, wrapper, alias, route, or policy.

Per-aggregate matrix

Every aggregate requires:

  • exhaustive state/input classification and complete action/settlement assertions;
  • an independently structured model using different vocabulary;
  • bounded exhaustive interleaving exploration;
  • property tests over longer sequences with invariants checked after every step;
  • fuzzing of stale, duplicate, foreign, overlap, cancellation, retry, shutdown, and wrong-generation facts as applicable;
  • debug and optimized replay;
  • compile-pass canonical construction and use;
  • compile-fail forged capabilities, tokens, identities, routes, and incomplete builders wherever those values are application-constructible or type-distinct;
  • deliberate inversion for every law-sensitive regression;
  • complete drain from every live phase;
  • no lost affine value, duplicated terminal outcome, or inferred provenance; and
  • no production panic for ordinary exhaustion or rejection.

Tests assert the complete Actions value or an independent trace. They do not discard actions, predict private nonces, copy implementation branches into the model, or put required transitions inside assertions.

Compile-time denial does not manufacture instance identity. When two actor instances intentionally share one concrete protocol, same-signature foreign correlations remain well-typed and their owning aggregate must reject them as stale without mutation. The compile contract instead prevents application forgery, duplication of affine authority, and substitution across genuinely different semantic types.

Shared-model gate

One independent law suite runs unchanged against every proposed consumer. A shared model is rejected if any consumer needs a mode flag, ignored result, placeholder, weakened error, alternate ordering, or special terminal policy. Extraction follows the second real consumer and must remove more semantic machinery than it adds.

Generic interpretation additionally requires two unrelated catalogue templates and two wrapper orders with no placeholder settlement event or per-template adapter. The real Bombay integration probe must conserve every affine value through the unchanged single Driver and retirement barrier.

Clean-room gate

Before deletion, preserve implementation-independent black-box traces, compile denials, adversarial cases, independent model expectations, and performance workloads. Commit that evidence separately, then create one explicit legacy deletion commit.

After deletion verify that every scoped symbol is removed or classified outside scope, no replacement module imports the baseline implementation, no legacy alias or alternate application path remains, and characterization tests cover every retained law. Deliberate policy changes are documented and tested rather than hidden as compatibility regressions.

DevX and performance evidence

Compare meaningful application lines, annotations, aliases, turbofish, structural concepts, public spellings, diagnostic size/distance, compiler time, monomorphization, binary size, allocations, and representative throughput. Define workloads and measure noise before judging differences. Code reduction is never inferred from a net-positive production delta.

Repository gates

All Rust/Cargo commands run through the pinned Nix environment. Feature-local gates precede the full matrix:

nix develop -c cargo nextest run --workspace
nix develop -c cargo fmt --all -- --check
nix develop -c cargo clippy --workspace --all-targets -- -D warnings
nix flake check

Applicable rustdoc, compile-fail, exhaustive, property, fuzz, benchmark, optimized, mutation, and model-checking gates are additional requirements, not substitutes. Candidate fixed point requires two consecutive fresh adversarial whole-repository audits with no credible untested high-value hypothesis.

Atomic actor downstream impact (engineering record)

Status: current read-only impact report after H591. This document assigns the remaining integration work; it does not authorize writes to a sibling repository and does not add a compatibility layer to Behavior Actors.

Result

The finalized behavior algebra has one direct runtime migration owner: Bombay. Bombay must interpret the complete typed Actions value and carry terminal behavior/environment custody through its existing Driver. Bombay Entity has a later owner-side migration away from the pre-0.13 Behavior protocol wrapper. Mnesis-Bombay has no direct atomic-actor call site; after Bombay's Entity surface is released, it changes only its typed Entity projection and keeps durable command completion and retry independent from actor lifecycle.

Consequently no downstream evidence requires restoring Proxy, Supervise, WorkerPool, KeyedWorkerPool, WorkerStopped, WorkerCreationResolved, or another removed atomic compatibility spelling in this repository. ActorInterface is also not a prerequisite for action settlement, terminal custody, Entity migration, or Mnesis durability.

Audited checkouts

The source trees were inspected in place and remained read-only. Because each sibling contained pre-existing work, both the Git identity and dirty-path count are part of the evidence boundary.

CheckoutAudited revision and worktreeSelected Behavior/runtime generation
Bombayccfb8f695c475e5d812ae735d610de59b1d127aa, dirty refactor/address-integration, 86 pathsworktree manifest/lock select Behavior and Behavior Actors 0.14.0 plus macros 0.11.4 at 75a317235710f5e5ae2dba02f0600673764cf728
Bombay Entity68d0f503205a569ddda88124f5add8e8a652e18f, dirty release-plz-2026-08-12T18-06-22Z, 2 pathsBehavior 0.9.1
Bombay Entity Runtime442e735523f2591fa9d2c735834435afa8f51530, dirty feat/entity-runtime-v1, 9 pathsBehavior =0.9.1
Mnesis-Bombay9d567f6d4f113bf3ac5ffeb569c219efb0ecf160, dirty main, 5 pathsreleased Bombay 0.1.0, Behavior 0.9.5, Bombay Entity 0.1.0, Mnesis 0.3.1

The finalized atomic worktree is at 50a226803ccf26673a6f08e99d189fe77870cb09. Bombay's selected 75a3172 revision is an ancestor of it and therefore is not the finalized build contract. Bombay's manifest/lock selection must first move to the retained revision or a release containing it. Some dirty Bombay design records mention other interim revisions; the manifest and lock are the actual audited build selection.

Exact source trace

Bombay

Bombay is already the sole concrete runtime owner, but the audited source still implements the older effect contract:

  • crates/bombay/src/interpret.rs defines a two-leg InterpretationError<Creation, Send>. CommitActions::commit loops over creations, then calls InterpretSends, returns Result<(), _>, and retains no complete accepted/rejected/blocked/corrupt/unattempted settlement.
  • crates/bombay/src/application_runtime.rs contains 21 legacy SendInterpreter, InterpretRequest, delivery, and child-input implementations. CreationResults correlates by a raw nonce in a HashMap, rather than by typed occurrence plus CreationId. spawn_child reports the older CreationResolved result and publishes a child only after the old launch path completes.
  • Seven production sends discard the ControlSender::send result across application_runtime.rs, reports.rs, and observation.rs. Those sites can lose the exact source result, child fact, parent report, or observation event when admission has closed.
  • crates/bombay/src/local.rs makes CommitActions return only Result<(), E>. ActiveEnvironment::retire drains and drops resources and returns unit.
  • crates/bombay-engine/src/driver.rs returns only Completion or DriverError; crates/bombay-engine/src/environment.rs fixes retirement to unit. The final concrete behavior and environment residual therefore do not cross the retirement barrier.
  • crates/bombay/src/incarnation.rs, retirement.rs, generation.rs, and launch.rs reduce the terminal result to an exit/crash classification. Child tasks are awaited, but their complete stopped behaviors and unresolved settlements are not transferred to a parent or root custodian.
  • crates/bombay/src/application.rs begins with Application::new(root) and appends application children afterward. Atomic templates whose root construction needs an installed lifecycle or diagnostic capability require the inverse, role-first order.

This is a contract migration, not evidence for a second runtime. Bombay's one Driver, Communication mailbox, Address lease, Observe facts, Timers queue, child host, and executor task hierarchy remain the concrete owners to extend.

Bombay Entity and Entity Runtime

The canonical Bombay Entity checkout pins Behavior 0.9.1 and its crates/entity/src/protocol.rs directly composes WorkerStopped and WorkerCreationResolved with the old Addr/Msg, turn-less transition, and positional-send Behavior contract. The secondary Entity Runtime worktree has the same dependency generation and direct spellings in crates/entity/src/behavior.rs.

Those wrappers are not atomic actor owners. The migration retains the runtime-neutral Entity laws—stable EntityId, single-flight activation, generation-safe replacement, bounded admission, ordered drain fence, passivation, and exact-incarnation retirement—but deletes the obsolete protocol wrapper. Bombay then hosts the application's current concrete Protocol directly and owns the private FIFO fence ingress. Updating either Entity checkout to current Behavior in isolation would create two runtime generations and is rejected.

The canonical migration target is the Bombay-owned Entity surface. The secondary Entity Runtime worktree is comparison evidence, not an additional runtime to preserve or migrate independently.

Mnesis-Bombay

No scoped atomic aggregate or removed atomic spelling occurs in Mnesis-Bombay production source. Its only current Bombay-facing production boundary is:

  • crates/bombay/src/routing.rs: Addressed<A::Id, Message> becomes (bombay_entity::EntityId<A::Id>, Message) without changing the payload; and
  • crates/bombay/src/transport.rs: ExecuteRequest<Request, Reply> keeps the runtime-neutral command request separate from Bombay's typed reply capability.

The behavior dependency is present in the released graph but no production module interprets Actions or names an atomic actor. Mnesis owns load, decide, append, optimistic-conflict handling, command identity, and durable outcome. CommitFailure::Ambiguous and the uncertain_append_failure_returns_command_identity_without_retry regression already prove the critical separation: a restart may restore availability, but cannot prove whether an append committed and cannot authorize transparent retry.

After Bombay releases its owned Entity family surface, Mnesis-Bombay replaces the standalone EntityId projection/dependency with the Bombay-owned typed Entity reference projection. It must preserve the command unchanged and keep Bombay admission/termination outcomes distinct from CommandOutcome. It does not gain a supervisor, atomic actor, behavior interpreter, Entity directory, mailbox, or persistence effect inside Behavior.

Required Bombay work by owner and order

The normative details remain in atomic-runtime-settlement.md. The executable downstream sequence is:

OrderOwner and exact filesRequired observable changeExplicit non-requirement
0Bombay Cargo.toml, Cargo.lock, Engine fuzz manifest/lockselect the retained Behavior/Core, Actors, and macros revision as one familyno mixed revision, local compatibility fork, or floating sibling path
1crates/bombay/src/interpret.rs; crates/bombay/src/application_runtime.rsreplace the two-leg/unit commit with one actions.interpret call and exact InterpretItem results for every statically known itemno universal runtime error, aggregate switch, erased envelope, or positional traversal
2application_runtime.rs, child_bindings.rs, local.rs, launch.rsroute each creation batch once; establish children independently; retain ChildCreationOutcome; commit initialization settlement before publication/ingressno nonce-as-identity, overwrite, rollback of an accepted prefix, or atomic-template host
3interpret.rs, application_runtime.rs, reports.rs, observation.rs, local.rsadmit source-action and creation settlements in declared order; recover a closed control event exactly; retain the current value and untouched suffix after closureno ignored send result, recursive actor call, detached task, callback, or second mailbox
4application_runtime.rs, local.rs, launch.rshost InitializeWorker on the installed child and BeginActivation in the existing typed task product; enqueue Started before polling and return the exact terminal inputno activation work in a behavior and no erased future/task collection
5application_runtime.rs, time.rs, selected bombay-timers ownerimplement total scheduling receipts/rejections and preserve exact scheduling results through the generic source-result pathno FixedSupervisor timer branch and no panic/exhaustion sentinel
6crates/bombay-engine/src/environment.rs, driver.rs; Bombay local.rs, launch.rs, incarnation.rs, retirement.rs, generation.rs, application_runtime.rscarry the final concrete behavior plus typed environment residual through the existing retirement barrier, parent admission, and a non-rejecting root custodianno dropped terminal behavior, log-as-custody, second Driver, or alternate lifecycle service
7crates/bombay/src/application.rs, application_runtime.rsdeclare/install application actors by semantic role, obtain typed capabilities, then construct and activate the pure rootno MailAddr, structural occurrence path, explicit composed root type, dummy field, registry, or capability lookup in application syntax

Orders 1–6 are one coherent custody contract: applying only the interpreter syntax while leaving unit retirement still loses affine values. Order 7 is a separate Bombay responsibility and may be developed independently, but both must converge before an end-to-end atomic application is claimed.

The generic item implementations in order 1 include logical/exact/child delivery, observation, shutdown, scheduling, ReportToParent, source actions, atomic diagnostics, CustomerDelivery, worker preparation, initialization, and activation. They are capability-family implementations, not branches for StableProxy, FixedSupervisor, DynamicSupervisor, FIFO, or KeyedPool.

Downstream dependency order

retained Behavior + Behavior Actors release
    -> Bombay total interpretation and retirement custody
    -> Bombay role-first application assembly
    -> Bombay-owned Entity lifecycle/application surface
    -> Mnesis-Bombay dependency and typed projection migration

The five local atomic aggregates do not wait for Entity or Mnesis. Their end-to-end runtime claim waits only for the separately authorized Bombay custody/application work. Entity and Mnesis then consume the released Bombay surface in their own campaigns.

Acceptance evidence for the downstream implementation

Bombay must provide caller-visible regressions before its production migration:

  1. every accepted, rejected, blocked, corrupt, and unattempted item returns its exact complete value in both relevant wrapper orders;
  2. semantic creation rejection permits independent later work but blocks only the exact child-dependent item;
  3. heterogeneous creations preserve their branch, occurrence, CreationId, current child, initialization actions, and exact reason;
  4. initialization actions settle before publication and ordinary ingress, including initialization that selects Step::Stop;
  5. source results run to quiescence in declared order, and closed admission returns the current value plus untouched suffix;
  6. child-to-parent and parent-to-root closure injections preserve exact terminal custody;
  7. the unchanged single Engine Driver returns the final behavior and typed environment residual through its retirement barrier;
  8. a role-first DynamicSupervisor Stop { key } application compiles without explicit worker/activation types or fabricated values; and
  9. the selected Entity and Mnesis suites run separately against their released graphs until the owner-side release migration is complete.

Excluded campaigns

ActorInterface, external actors, receptionists, HTTP, discovery, clustering, process-exit policy, durable inboxes, committed-event relays, and distributed Entity directories remain independently owned work. The dirty Bombay checkout contains ActorInterface and native Entity experiments, but neither changes this report's dependency assignment and neither authorizes an actor-algebra compatibility seam.

Aggregate-drift checkpoint

This audit changes no production state, protocol, transition, or public spelling. H591's five transition authorities and measured family rows remain unchanged: StableProxy 8 control alternatives; FixedSupervisor 5 roster alternatives; DynamicSupervisor 2 availability plus 14 entry alternatives; FIFO 5 pool states; KeyedPool 5 pool states. Every exact creation, settlement, activation, lifecycle, command, and durable-outcome value retains its existing owner. Arrival history, repeated causes, false cardinality, nested transition authority, semantic booleans, dynamic escape, and structural user syntax remain zero. Disposition: pass.

DevX research cross-audit for atomic supervisors and pools (engineering record)

Historical evidence snapshot: this record was last committed at 1f20cc4. Its verdicts describe that revision; the current repository quality audit tracks later verification and unresolved integration work.

This audit was performed after the feature catalogue, solution, DevX target, minimal core decision, and type equations were written. The research corpus is evidence and a dead-end register; it is not an architecture to copy.

Source corpus: /Users/joel/Code/devrandom/bombay/research/devx-usability-loop.

Scope read

The audit covered every research document and the machine-readable campaign inventories:

  • GOAL, REQUIREMENT-AUDIT, INVARIANT-MATRIX, BASELINE, PROGRESS, HYPOTHESES, and ACTOR-TEMPLATE-AUDIT;
  • DEAD-ENDS, RUST-AUTHORING-MECHANISMS, ORDINARY-AUTHORING, OUTER-AUTHORING-PROBE, MACRO-LAST-COMPARISON, and PERFORMANCE;
  • APPLICATION-TOPOLOGY-CONTRACT, SHUTDOWN-PLAN-AUTHORING, ESTABLISHED-CREATION-BLOCKER, REPOSITORY-AUDIT, and RUNBOOK;
  • ENTITY-OBSERVE-LEVERAGE, ENTITY-INTEGRATION-CROSS-VERIFICATION, FRAMEWORK-COMPARISON, and SOURCES;
  • evidence.json, framework-corpus.json, ratchets.json, both checking scripts, and the four stable-Rust mechanism probes.

Generated Cargo build output and captured compiler stderr are evidence owned by their reports; they are not separate design documents.

Relevant research laws retained

Research findingAtomic-actor consequenceCatalogue/solution coverage
A Behavior transition may only return typed Actions; Tokio sends, clocks, hydration, and callbacks inside the fold are invalid.All five templates are direct pure folds. Activation is an interpreter transaction and time arrives as typed facts.SH-ACTOR, SH-READY, EFFECT, VERIFY
Creator-local nonce/occurrence is correlation, not actor identity. Successful installation must retain the exact committed capability, and collision is rejection rather than replacement.Proxy/supervisor/pool creation reserves correlation before commit, observes explicit acceptance/rejection, and never derives incarnation identity from a nonce.SH-CREATE, SH-CORRELATE, PX-INIT, PX-REPLACE
Same-action creation is interpreted before dependent child delivery/observation.This governs ordinary behavior-authored creation actions, but it does not make initialization effects transactional. A worker host commits installed-but-not-ready before its initialization Actions are interpreted; later rejection drains the installed incarnation and cannot roll back prior effects.SH-CREATE, SH-READY, proxy causal design
Logical, established, and mixed routes are different static capabilities. Selecting an exact runtime variant does not erase a logical host requirement.Lifecycle, customer, diagnostic, and reply routes preserve their concrete DeliveryRoute; no template silently upgrades a logical identity.SH-STATIC, SH-DELIVERY, FS-BUILD, DS-BUILD, FP-BUILD
BAX6: a supervised domain command can become unavailable after mailbox admission, and a terminal fold error is not an observable customer rejection.The stable proxy must retain the full original sender/command and emit one typed unavailability fact. Delivery rejection has an explicit ownership law.PX-ROUTE, FS-FACTS, SH-DELIVERY
BAX7: proxy installation and worker facts can arrive in either order; assuming creation resolution precedes a child report is invalid.The proxy alone joins worker creation, initialization, activation, and stop facts order-independently. Fixed/dynamic owners receive one atomic proxy outcome; direct pools own their corresponding closed joins. No pair of flags coordinates them.SH-READY, PX-ACTIVATE, FS-FACTS, DS-START, FP-TOPOLOGY
BAX10: pool shutdown must run through the pool-owned lifecycle path and return every owned accepted job.FIFO/keyed draining closes admission, settles assignments/queues, drains direct workers, and emits exact forced facts under the selected deadline policy.SH-SHUTDOWN, FP-SHUTDOWN, KP-END, EFFECT
A terminal supervision report is not a causal acknowledgement that the supervisor has stopped. Waiting on its termination before requesting shutdown is circular.Lifecycle facts, delivery attempts, and actor termination are separate observations. Shutdown always has its own typed policy and completion.SH-DELIVERY, SH-SHUTDOWN, FS-SHUTDOWN
Public examples must not expose generated products, structural selectors, nonces, effect paths, actor-space products, or shutdown coordinator representations.Ordinary supervisor/pool source sees builders, domain values, policies, and public protocols only. ReportToParent is hidden behind assignment.complete.API, DevX document, minimal-core visibility rule
Builders/typestate are acceptable only when they express real missing/selected semantic choices and compile diagnostics are measured.Builder proof markers remain inferred/private; there is one canonical documented call order and no type per builder axis.API, type inventory
Macros are last resort and may generate syntax only; a macro cannot resolve associated-type identity or repair a missing semantic composition.No supervisor/pool macro, definition trait, or generated ownership engine is selected. Compile prototypes precede any syntax mechanism.API, NONFEATURE
Exact external reply requires a real typed endpoint; admission is not execution or durable completion.Request reply, durable lifecycle ownership, customer outcome, diagnostic outcome, and activation readiness remain separate capabilities/facts.SH-DELIVERY, DS-START, FP-COMPLETE
Async Entity hydration completes before routability; installation alone is insufficient.The same general lifecycle distinction is required for every worker incarnation without importing Entity machinery into actors.SH-READY, PX-ACTIVATE, all worker-owning templates
Family capacity research distinguishes waiter, hydration, residency, and binding bounds.Dynamic entry capacity, pool backlog, keyed binding capacity, and activation authorization are independent named policies. The authorization count has one law; supervisors reserve earlier than pools because their proxy outcome is opaque.SH-READY, FS-TOPOLOGY, FS-TIMING, DS-START, FP-TOPOLOGY
Forced retirement must preserve exact provenance; Drop, abort, logging, or a coarse crash is not orderly completion.RetireActorGraphAfter produces typed per-child/per-job forced-retirement facts, transfers outstanding ownership, and counts the member actor-side drained. A root run future remains live until transferred external work and late exact drains settle.SH-SHUTDOWN, actor shutdown sections

Research results deliberately not copied

Several historical successes are dead ends for the new atomic design.

Old pool complete_to capability

ORDINARY-AUTHORING treated an assignment-carried complete_to recipient as an improvement over a fabricated address. It is still unsafe: a worker can substitute another capability of the same protocol. The new law is stricter: the worker receives an opaque pool-issued token, and only the pool retains and selects the customer route. Stale results use a separate diagnostic lane.

Existing supervisor/pool recipes

The catalogue demonstrates feature intent and interpreter seams, but its ChildTopology, stable-proxy ingress plumbing, ownership/fleet/slot types, positional effect paths, and nested wrapper equations are not retained. The new architecture re-derives five direct folds from laws.

Universal behavior-layer composition

The research showed useful independent wrappers such as stash, timeout, and shutdown adaptation. That does not imply that a supervisor or pool is a stack of tiny behaviors. Each atomic template owns one coherent state machine and one action product. Orthogonal wrappers may still surround the finished actor.

Entity and topology machinery

Entity families, application host normalization, Axum boundaries, Mnesis durable outcomes, named application shutdown plans, and external ask are separate owners. Their discoveries inform readiness, capability, and shutdown laws, but their registries/directories/typestate must not be moved into supervisors or pools.

Framework APIs

OTP/Akka/Pekko/Orleans/Ractor comparisons corroborate lifecycle and supervision concerns. They are not semantic authority for Bombay and do not justify an untyped mailbox, dynamic registry, callback API, virtual actor, cluster pool, or another framework's restart defaults.

Complete dead-end disposition

The following dead-end families remain rejected:

  • universal ingress inflation for all actors;
  • a giant universal installation/hosting type equation;
  • unindexed recursive type lookup and structural-key requirements on arbitrary domain types;
  • protocol normalization by explicit positional allocation, keyed tries, or a closed local macro;
  • per-role protocol/address spaces;
  • an unconstrained shutdown target sum or a second shutdown DSL;
  • positional paths hard-coded through Guardian/wrapper depth;
  • direct Tokio reply, callback, channel, task, or clock effects inside a fold;
  • using termination as a supervision-report acknowledgement;
  • hard-coded parent paths or exposed ReportToParent in worker code;
  • supervision rejection that discards the original command;
  • readiness/restart provenance inferred from runtime ordering;
  • a fabricated public proxy ingress that cannot return unavailable commands;
  • a synchronous factory pretending to support asynchronous hydration;
  • hard-coded outer StopOnShutdown around an already authored lifecycle;
  • dynamic registries, dyn, boxed behaviors/futures, Any, TypeId, and erased envelopes;
  • per-family or nonce-derived address namespaces;
  • target-as-origin external delivery;
  • abort-on-drop as normal lifecycle ownership;
  • a single undifferentiated capacity counter;
  • unbounded per-identity telemetry or tombstone tables;
  • making Discovery or Entity mandatory for local supervision;
  • treating private observation, mailbox admission, actor termination, or a customer reply as durable command completion;
  • a macro, alias, extension trait, builder stage, or callback whose only job is to move current compiler plumbing to every caller.

Features added or corrected because of the audit

The research audit changed the documents in these material ways:

  1. installation became an authoritative installed-but-not-ready host commit before initialization effects, followed by settlement, activation, and readiness, with distinct pre- and post-commit failures;
  2. no worker is advertised or assigned before Ready;
  3. pool completion now carries an opaque token rather than customer authority;
  4. stale completion became a diagnostic-only outcome, preserving the one-terminal-customer-outcome law;
  5. delivery attempt, delivery rejection, state commitment, and rejected payload recovery are specified separately;
  6. dynamic entries, keyed bindings, active correlations, and queues gained capacity/retirement/generation laws;
  7. shutdown gained exact ActorDrainPolicy alternatives WaitForActorGraph and RetireActorGraphAfter { deadline }, explicitly separate from process exit;
  8. dynamic request replies were separated from durable lifecycle ownership;
  9. fixed supervision gained status/snapshot requirements and optional lifecycle events;
  10. FIFO fairness became an exact circular-cursor algorithm;
  11. retry is documented as at-least-once execution; and
  12. typestate and fluent syntax were demoted from selected API to a hypothesis requiring compile-pass/fail and diagnostic measurement;
  13. every pool readiness/recovery transition must dequeue older eligible work before it can commit an idle worker;
  14. keyed admission became a total projection over every member phase;
  15. root-run completion now waits for transferred residual activation and late drain ownership rather than returning a dead error value; and
  16. terminal projection and same-action effect dependency now have explicit static equations whose Rust realizations remain prototype blockers.

Remaining blockers after the audit

The research does not determine these Bombay policy/integration questions. The specification has selected semantic answers for activation permits, logical cancellation, typed host settlement, and non-recursive diagnostic termination; their retained-core and interpreter realizations remain open:

  1. the smallest concrete association of activation permit/request/resolution with installation and initialization without adding hidden behavior effects;
  2. end-to-end typed host settlement for logical, exact, child, parent, lifecycle, customer, and diagnostic deliveries, including total heterogeneous terminal lifting and outward transfer through wrappers;
  3. creation-scoped dependency lowering from current Actions without paths, lookup, or a general runtime graph;
  4. RetireActorGraphAfter interpretation while non-cancellable external activation remains in flight, with the root run future owning residual settlement until it is empty;
  5. a minimal public protocol/type spelling for status, management replies, durable lifecycle events, and pool acceptance/terminal outcomes; and
  6. compile-pass/fail prototypes proving canonical builders without turbofish, public proof markers, aliases, ReportToParent, or path-counting.

These rows remain Open in the solution matrix. No production symbol is authorized until its law, ordinary syntax, focused regression, lower-order composition, and interpreter witness are recorded.

Disposition of every other actor template (engineering record)

The five supervisor/pool actors are not a reason to delete the rest of crates/actors. Most other templates own different, smaller transition laws. They should remain independent. This audit classifies the current source and prevents the supervisor/pool rewrite from becoming an accidental catalogue rewrite.

No production deletion or migration is authorized by this document. Each Update row needs its own law and regression after the five atomic actors are designed; it must not be folded into their implementation stage.

Dispositions

  • Keep — distinct law; no dependency on legacy supervisor/pool machinery.
  • Keep, cross-cutting update — distinct law, but it inherits a newly found delivery, capacity, retention, readiness-name, or lifecycle gap.
  • Replace — its feature belongs to one of the five new atomic actors.
  • Remove after migration — structural plumbing exists only to support the legacy supervisor/pool architecture.
  • Internal infrastructure — not an actor template and not ordinary DevX; retain only while a concrete interpreter/composition proof needs it.

Composition and lifecycle

Current familyDispositionReason / required change
Activate / Initialized / ActiveKeep as advanced pure-fold toolingIt proves one-time synchronous Behavior initialization only. Rename no type, but documentation must say it is not worker activation/readiness.
MessageAdapterKeep, cross-cutting updateA real typed message transformation. It must inherit rejected-delivery ownership for logical, established/exact, and occurrence-aware creator-local child destinations. An adapter with no birth capability cannot fabricate or reconstruct a ChildRoute; the creating owner must carry the exact occurrence proof through the named effect lane.
MachineKeepA direct finite-state/defer/replay actor with its own law. It is not supervisor behavior composition.
StashKeepA genuine transparent wrapper with replay and initialization-order laws. It is not a component of the new atomic actors.
StopOnShutdownKeepOrthogonal shutdown-ingress wrapper. Supervisors/pools own their internal drains and may themselves be wrapped only when the composition law is explicit.
FinalizeOnShutdownKeep, cross-cutting updateOrthogonal finalization wrapper; final-send rejection must not be confused with successful finalization.
Watch / LinkKeep, cross-cutting updateExact/logical peer observation is a distinct capability. Observation and reaction delivery rejection need typed ownership.
termination monitorsKeep, cross-cutting updateExact/logical observation plus cleanup/publication is distinct. Publication rejection must preserve its fact.
terminal propagationKeep, updateGeneric propagation remains valid, but the current supervision-specific terminal reason sum must be reshaped around the new recovery/forced-retirement outcomes.
homogeneous shutdown coordinatorKeep, update separatelyIt owns dependency-ordered child shutdown. It needs an explicit stuck-child/deadline law if it promises completion; it is not reused as the internal pool/supervisor drain engine.
heterogeneous shutdown coordinator and child-shutdown builderKeep, update separatelyStatic heterogeneous application shutdown is a different topology problem. Keep its exact-role law; do not copy its public proof-state taxonomy into atomic builders.
TaskKeep, cross-cutting updateOne-shot typed task/result actor. Result delivery rejection must preserve the owned result.

Discovery

Current familyDispositionReason / required change
ResolverKeep, cross-cutting updateImmutable finite bindings supplied at construction. Only reply-delivery rejection is newly shared.
RegistryKeep, updateMutable key bindings are a distinct discovery law, but the current Vec has no capacity policy. Add bounded admission/removal semantics and rejected-reply ownership in its own stage.
TopicKeep, updateTyped membership/broadcast is distinct. Current subscriber growth is unbounded; add membership capacity and delivery-failure disposition.
PubSubKeep, updateTyped topics/subscribers are distinct. Current topic table is retained even when empty and both dimensions are unbounded; add topic/member capacity and topic-retirement law.
PresenceKeep, updateVersioned presence/expiry is distinct. Current expired tombstones and participant table can grow forever; add bounded retirement/generation rules and reply-delivery rejection.

These actors do not become Entity, supervisor, or pool services. Their logical host requirements remain a separate application-topology concern.

Operational and state actors

Current familyDispositionReason / required change
Configuration and Features aliasKeep, cross-cutting updateSingle versioned configuration state; only reply-delivery rejection is shared. Features remains an alias, not a second actor.
HealthKeep, cross-cutting updateFixed component-health evidence is independent. Preserve exact evidence and rejected report ownership.
current Readiness actorKeep, rename/updateIt means versioned readiness of a declared dependency set, not incarnation activation. Prefer the public name DependencyReadiness so the new Installed → Activating → Ready lifecycle cannot be confused with it.
CacheKeep, cross-cutting updateBounded in-memory cache is independent. It is not durable persistence; module/docs should stop implying durability, and result-delivery rejection must preserve values.

Moving Cache out of a persistence taxonomy is a documentation/module API decision for a later contained stage. It is not necessary to implement the atomic actors.

Routing and admission actors

Current familyDispositionReason / required change
AcknowledgementsKeep, updateMulti-party acknowledgement is distinct. Completed/cancelled records are currently retained forever; add capacity, retirement, and key-reuse generation laws.
BufferKeep, cross-cutting updateBounded deferred delivery is distinct. Update target/outcome rejection ownership.
CircuitBreakerKeep, cross-cutting updateClosed/open/probe and timer correlation are independent. Update attempt/outcome delivery rejection; do not merge its timer logic into supervisor recovery.
CorrelatorKeep, updateBegin/resolve/cancel correlation is independent. Terminal keys are currently retained forever; add bounded retirement/key-reuse laws and rejected-result ownership.
DeduplicatorKeep, cross-cutting updateAlready has explicit positive capacity/eviction. Update target/outcome delivery rejection only.
OrderGateKeep, updateMonotonic ordered release is independent. Its held BTreeMap is unbounded; add admission capacity and rejected-release ownership.
PriorityQueueKeep, cross-cutting updateAlready bounded with typed token exhaustion. Update target/outcome delivery rejection.
RateLimiterKeep, cross-cutting updateFixed token-bucket state is independent. Update target/outcome delivery rejection.
Router and static strategiesKeep, updateRecipient routing is not worker ownership. Current mutable membership can grow unbounded; add capacity/removal policy and delivery rejection. Strategies remain pure values, not actors.
SequencerKeep, updateOrdered gap release is independent. Future-position retention is unbounded; add gap/capacity/retirement law and target/outcome rejection.
WorkQueueKeep, clearly distinguish, updateIt routes values to externally announced one-use worker routes. It creates no workers, observes no lifecycle, owns no completion, and performs no recovery. Therefore it is not a pool and the new pool must not contain it. Add delivery-rejection ownership; consider a less ambiguous public name only in a separate migration.

The shared observation is not “make all routing actors use queue/correlation utils.” It is that several independent actors currently omit capacity or delivery-rejection laws. Each keeps its own direct fold and uses only a truly general interpreter capability once that capability is designed.

Timing

Current familyDispositionReason / required change
OneShotKeepTransparent single-timer wrapper with exact identity/generation.
PeriodicKeepTransparent repeated-timer wrapper with its own rescheduling law.
DeadlineKeepAbsolute-deadline wrapper; distinct from supervisor drain policy.
ReceiveTimeoutKeepMailbox-activity-reset timer wrapper; distinct from backoff or drain deadline.
LeaseKeep, cross-cutting updateOne bounded lease state machine with exact timer generation. Update outcome-delivery rejection.

Timer IDs/generations and scheduling requests remain neutral interpreter carriers. The new actors reuse them; they do not copy these wrappers or form a generic scheduler component.

Workflow

Current familyDispositionReason / required change
BarrierKeep, cross-cutting updateFinite declared membership and generation law are independent. Release-delivery rejection must preserve participant outcomes.
LatchKeep, cross-cutting updateFinite countdown/waiter law is independent. Release-delivery rejection must preserve waiters.
WorkflowKeep, cross-cutting updateFinite dependency graph and step-state machine are independent. Outcome-delivery rejection must preserve the exact workflow result.

Legacy supervision and pool surface

Current source/surfaceDispositionReplacement
supervision/adapter/proxy.rs, current Proxy, ProxyEvent, ProxySends, ProxyUnavailableReplaceNew stable proxy direct fold and its minimal control/report sums.
Supervise wrapper and fixed/backoff recipesRemove after migrationFixed supervisor already owns supervision; applications should not assemble it from a wrapper/proxy/report stack.
current fixed Supervisor and fixed_supervisor.rsReplaceNew fixed supervisor typestate definition and direct fold.
current DynamicSupervisorReplaceNew dynamic supervisor with order-independent readiness, capacity, cancellation, generations, and durable lifecycle ownership.
supervision/domain/{fleet,incarnation,ownership,restart_budget}.rsRemove after migrationPrivate state belongs in each new direct actor. Pure recovery policy arithmetic may be rewritten once and shared only if two independent folds prove identical laws.
ChildTopology, FixedFleetOwnership, slot/fleet/ownership typesRemoveRuntime roles/members are actor-private values, not a universal ownership model.
current RestartConfiguration, RestartPolicy, RestartTiming, Backoff splitReplace/consolidateMinimal Recovery, Strategy, RestartLimit, and RestartRelease sums.
current pool.rs, WorkerPool, KeyedWorkerPool, aliases and eventsReplaceSeparate direct FIFO and keyed pool folds with no supervisor/proxy nesting.
protocol/pool.rs, WorkerPoolProtocol, KeyedWorkerPoolProtocolRemove after migrationNew nominal public pool protocols selected by compile prototypes.
current PoolAssignment, PoolCompletion, PoolCustomer, job/assignment IDs, pool response/rejection/failure sumsReplaceOpaque completion token, pool-retained customer route, one customer terminal outcome, separate diagnostics, private correlations.
composition/report_relay.rsRemove after migrationIts only production consumer is the legacy pool's proxy/report stack. New direct pool workers complete through the pool-issued token; supervisors receive direct proxy reports.
supervision-specific protocol values in protocol/mod.rs (WorkerCreationResolved, WorkerStopped, replacement/report wrappers)Remove/replaceNeutral CreationResolved, ChildStopped, exact activation facts, and actor-private control/report sums.
supervision/pool-specific LogicalDeliveryProtocols implementations in requirements.rsRemove/replaceNew named actor products receive only their exact static requirement projections. The generic projection mechanism remains internal infrastructure.
SupervisionFailureReason, RestartDenial, and supervision terminal reportingUpdate, do not blindly deleteExact terminal provenance is consumed outside supervision. Reshape it to the new recovery, activation, delivery, and forced-retirement outcomes; remove legacy-only variants and coarse factory failure.

Neutral infrastructure kept under audit

The following are not “other atomic templates”:

  • DeliveryRoute and exact/logical recipient products;
  • neutral creation, observation, child shutdown, timer, and terminal facts;
  • generated event/send products and static logical-host projections; and
  • occurrence/position machinery required by closed child products.

They remain in the minimal-core/interpreter audit. Atomic actor builders and ordinary examples must not name their structural paths or product nesting.

Result

The catalogue does not need a mass deletion. The clean boundary is:

  1. replace the complete legacy supervision/pool island;
  2. remove structural relays and supervision-specific protocols left with no consumer;
  3. retain independent actors and wrappers;
  4. later give every route-emitting actor the same foundational rejected-delivery law; and
  5. separately repair unbounded retention where this audit identified it.

Those later catalogue repairs must be staged independently. They cannot grow the supervisor/pool production change or become another universal utility module.

Actor-template composition audit (engineering record)

Historical evidence snapshot: this record was last committed at 1f20cc4. Its verdicts describe that revision; the current repository quality audit tracks later verification and unresolved work. The historical DeliveryRouteFor<Owner> proposals below were removed during the A13 review; current callers constrain DeliveryRoute's associated protocol address directly.

Authoritative redesign ledger

This section supersedes every historical "fixed" or provisional design claim later in this file. Those sections are retained only until the corresponding code and tests have been deleted; they are not completion evidence.

Laws

  1. BehaviorLayer constructs one concrete same-mailbox transformation. A higher-order behavior may apply the layer and may delegate the resulting behavior, but it may not inspect, remove, or restore a field inside another behavior's event or send product.
  2. Fixed topology, restart eligibility, restart budget, optional restart delay, timer generations, replacement retention, and shutdown cancellation are one state-transition law owned by FixedFleetOwnership. Delayed restart is configuration of that law, not a wrapper around arbitrary send shapes.
  3. A private parent/child communication is an explicit Actions effect. ChildInput targets one declared child occurrence; ReportToParent travels one established parent edge and the interpreter attaches the exact local child nonce. Neither operation fabricates a logical recipient.
  4. A report crossing two parent edges is relayed by one stateless behavior transformation. The relay owns exactly one input-to-effect law and neither interprets nor deduplicates the report.
  5. A pool worker receives only assignment data and reports only a completion. It does not name the pool's public protocol, customer reply route, pool behavior, stable-proxy behavior, or a logical recipient at the pool address.
  6. Logical hosting requirements are derived from real route selections and real composed templates. An application-authored dummy product is not evidence that a catalogue template is hostable.
  7. User-level composition tests observe complete interpreted traces. They may not manually transfer an effect into the next fold or assert structural .owned/.inner paths as proof of composability.

Deletion ledger

  • Delete SupervisionOwnership, BackoffSupervision, BackoffSends, and the application/standalone duplicate backoff surfaces.
  • Delete PoolAssignmentProtocol and remove WorkerPoolProtocol / KeyedWorkerPoolProtocol from worker assignment and completion types.
  • Delete Bombay's template-specific ParentReporting methods after the one generic parent-report interpreter is installed.
  • Delete metadata-only logical-host tests and every documentation claim they were used to justify.
  • Delete public aliases and With... names that only expose a concrete generic nesting and own no law.

Initial containment

exact blocker: delayed restart and pool completion currently depend on concrete
               supervision/pool product layouts
smallest regressions: one standalone delayed restart trace; one worker that
                      completes without naming a pool protocol
expected production files: Behavior Core effects/creation; shared supervision
                           ownership/protocol; proxy relay; FIFO/keyed pool;
                           Bombay report/action interpretation
expected production delta: net-negative after specialized paths are removed
new public semantic types: at most one restart-configuration sum, one generic
                           relayed report, and one pool completion value

Stored-layer removal checkpoint

Exact blocker: PoolWorkerLayer<L, R> stores an existing layer only so FixedFleetOwnership can apply it while staging initial stable children. It owns no state, event, effect transformation, or policy. The ownership fold does not otherwise use the layer: worker replacement is an explicit ChildInput<ReplacementRequested<C>> to the already-established stable child.

Invariant: fixed-fleet ownership owns lifecycle state and names the stable child type in its effects, while the containing behavior owns construction and supplies a borrowed BehaviorLayer only when initialization stages those children. Pool initialization may compose its user layer with the lawful RelayChildReports transformation in a local inferred closure; no stored adapter type is required.

smallest regression: FIFO and keyed pools stage RelayChildReports<L::Output,
                     C, PoolCompletion<R>> without PoolWorkerLayer
expected production files: ownership.rs, fixed_supervisor.rs,
                           adapter/supervisor.rs, pool.rs
expected production delta: net-negative
public API: +0 types / -0 types (PoolWorkerLayer is private and deleted)
reused laws: BehaviorLayer, RelayChildReports, FixedFleetOwnership,
             ChildInput<ReplacementRequested<C>>

Scope and decision rule

This audit covers the complete bombay-behavior-actors catalogue as it exists, not one commit or one pair of reported gaps. Git history is used only to identify when a public name or implementation shape appeared.

A reusable actor template is retained only when its own fold implements a distinct state-transition law or a distinct typed event/effect transformation. Sharing data structures or similar branches is not evidence that two actors are one template. Conversely, a constructor, alias, policy marker, or wrapper is not a template merely because it gives a long concrete composition a shorter name.

The governing semantic classification is Bombay policy. The actor-model laws remain serialized turns, finite acquaintance, fresh creation, and explicit communications/creations/next behavior. This audit does not change those laws. It changes how the library packages derived constructions around them.

Pre-edit change ledger

Exact blocker: the existing H37 audit treats “uses one shared implementation” as the success criterion. That criterion caused public policy markers, aliases, builders, and wrappers to be counted as actor templates even when they only select or nest existing folds. The smallest end-to-end regressions are the existing pure-fold constructions that already exercise StopOnShutdown, FinalizeOnShutdown, fixed supervision, delayed supervision, both pool laws, both shutdown-coordinator products, and Configuration<FeatureSet<_>> without requiring a second semantic template. Those constructions will remain and the bespoke names will be removed around them.

Expected surface:

  • 26 files directly name the redundant public surface; separating the pool, watch/monitor, and shutdown folds and updating exhaustive callers is expected to take the cumulative change above 15 files.
  • Production delta is expected to be net-negative, primarily from deleting the child-shutdown planner, policy-parameterized fixed-supervisor forms, recipe forwarders, and name-only lifecycle/feature specializations.
  • No new public type is expected. At least 20 public types/aliases/traits and seven forwarding functions are expected to be removed.
  • The retained folds are StopOnShutdown, FinalizeOnShutdown, Watch, TerminationMonitor, Supervisor, BackoffSupervisor, WorkerPool, KeyedWorkerPool, ShutdownCoordinator, and HeterogeneousShutdownCoordinator. Their existing typed products and interpreter requests are reused.

Universal layer composition redesign: stage 1 pre-edit ledger

The completed audit above proved individual template laws, but it did not provide one static construction contract by which a generic consumer can apply an arbitrary concrete behavior transformation and name its associated output. Callers can manually nest Stash<B>, Watch<B>, timing, shutdown, supervision, and other transformations, but frameworks must reproduce each constructor and spell or independently project the resulting concrete type. The same omission encourages higher-order templates to integrate lower-order policy instead of accepting an already-composed behavior.

The exact stage-1 blocker is therefore catalogue-wide, not a priority-queue or proxy special case. The smallest compile regression is a generic function that accepts any B: Behavior and any static layer L, applies L once, and returns the layer's associated concrete behavior without naming that output. Black-box witnesses must use unrelated real catalogue combinations, including routing inside supervision, persistence under timing/lifecycle transformations, and different wrapper orders. Tests must assert initialization, event ingress, all send and creation lanes, errors, phases, and next-behavior decisions—not just successful construction.

This is a deliberate Bombay construction law, not an actor-model guarantee:

  • a layer is a statically dispatched value-to-value construction from one concrete Behavior to another concrete Behavior;
  • the associated output retains its complete protocol, event, sends, birth, initialization, error, phase, and next-behavior algebra through ordinary Behavior associated types;
  • a layer performs no actor effect; only the resulting behavior's pure fold returns Actions;
  • inline layers retain the current actor namespace, while separately running behaviors still connect through transferable logical or established capabilities; and
  • ChildRoute<C, O> remains usable only by the topology owner whose direct birth algebra proves that occurrence.

Expected stage-1 surface:

  • at most eight files: this ledger, the minimal core construction contract and export, one generic-consumer suite, and directly affected documentation or compile tests;
  • production: at most +80 / -0 / net +80; this stage establishes the missing generic contract, while later template deletion must make the cumulative redesign production-negative;
  • tests: compile and pure-fold witnesses across at least three unrelated catalogue families and more than one layer order;
  • public API: one construction trait, no wrapper, builder, marker, effect product, dynamic dispatch, or new effect algebra.

The implementation must reuse the existing concrete wrapper types, EventLayer, SendLayer, Actions, Behavior::Birth, and their structural ingress proofs. A closure or concrete constructor may implement the common contract, so catalogue templates do not require a parallel family of *Layer configuration wrappers merely for inference. Before the later audit crosses 15 cumulative files, 500 net new production lines, or three new public types, its measured ledger must be reported at the mandatory checkpoint.

The higher-order state map driving the later deletion audit is:

OwnerIrreducible correlation retainedLower-order law currently duplicated or coupled
Proxyone fresh worker-incarnation installation/replacement relationshipcustomer return route is fixed to logical delivery
Supervisorfixed topology, restart provenance, and worker/proxy fact correlationfleet membership and terminal drain overlap registry/shutdown policies
DynamicSupervisortwo-producer initial-install join and replacement correlationmutable membership, customer correlation, and drain are integrated
delayed supervisorstimer generation to accepted replacement-batch correlationdelay progression is already a lower Backoff law
WorkerPoolassignment identity joined with worker return/stop factsFIFO backlog, availability routing, fixed supervision, and drain are integrated
KeyedWorkerPoolpersistent key-to-slot assignment and rebalance correlationinherits the same FIFO, routing, supervision, and drain machinery
shutdown coordinatorsactive phase to exact outstanding child-stop factsplan declaration/building is separate from phase execution

This table is a falsifiable work list, not a claim that every apparent overlap can be split without changing asynchronous semantics. Each deletion requires a real composition test that preserves ordering, ownership, and every effect lane first.

Universal layer stage-1 checkpoint

The generic construction regression failed on the baseline because no layer contract or associated output existed. BehaviorLayer<B> now provides that static associated output, closures implement it without allocation or erasure, and Behavior::layer supports inferred chaining. Real routing/supervision and persistence/stash/shutdown compositions pass in debug and optimized builds while retaining complete creation, observation, domain-send, and stop lanes.

production: +111 / -2 / net +109
tests:      +90 / -0 / net +90
docs:       +74 / -0 / net +74
public API: +1 types / -0 types

The production delta exceeds the pre-edit estimate by 29 lines because the single trait's rustdoc states the complete semantic boundary and includes a compile-checked generic-consumer example. It remains below every mandatory stop threshold. This is new generic capability code, not consolidation or code reduction; deletion work is a later independently measured stage.

Owner-scoped delivery checkpoint

DeliveryRouteFor<Owner> is the second static composition law. It selects the existing logical, established, or child delivery product without erasure. Recipient and EstablishedRecipient require the same address namespace as the owner; ChildRoute additionally requires Owner: ResolveChildOccurrence<Occurrence, Child = C>. A compile-fail test proves that NoBirths cannot claim a foreign child route. Proxy now uses this contract for its real worker-forwarding leg, so the trait is exercised by a production topology owner rather than existing only as test syntax.

The cumulative stage ledger is:

production: +245 / -8 / net +237
tests:      +180 / -0 / net +180
docs:       +96 / -0 / net +96
public API: +2 types / -0 types
changed files: 9

Focused layer and route regressions pass in debug and optimized builds; Behavior and Actors rustdoc/compile-fail tests pass; the workspace all-targets check is warning-clean. This remains capability work, not code reduction.

The next conversion applies the owner-scoped route contract to all caller-supplied delivery destinations (buffer, priority, ordering, sequencing, deduplication, rate limiting, and their shared named product) and updates their independent models. Together with affected public compile matrices this will cross the 15-file mandatory checkpoint. Production editing for that expansion must not start until the expanded surface is explicitly authorized.

Catalogue-wide composition axes

Queue and proxy are witnesses, not privileged composition categories. The catalogue has two orthogonal composition axes, and every retained template must be classified on both:

AxisStatic contractApplicability
same actor, inlineBehaviorLayer<B, Output = ...>every transformation that consumes one B and returns another concrete Behavior
separate actor, transferableDeliveryRoutelogical and established recipients passed between actors; the route projects its protocol and send product
topology-owner localDeliveryRouteFor<Owner>the same transferable routes plus a direct ChildRoute proven by Owner::Birth
runtime hosting projectionnot currently providedowner-authored repetition was rejected because it cannot prove transitive completeness

The direct-child case deliberately does not make ChildRoute transferable. A separate queue, router, workflow, or cache actor cannot send through another actor's child namespace. It connects to that topology through a logical or established proxy capability; the proxy then emits the proven child delivery. This is the same architecture for every catalogue family, not a proxy-specific exception.

The current endpoint audit partitions the full catalogue as follows:

  • transparent transformations (Stash, shutdown, timing, watching, termination propagation, supervision adapters, and shutdown coordination) must preserve every inner event, send, birth, phase, error, initialization, and next-behavior lane while adding only their owned law;
  • ordinary request/reply cores already parameterize customer return routes through DeliveryRoute, including persistence, workflow, operational, correlation, acknowledgement, presence, and admission-result actors;
  • payload-forwarding cores (Buffer, PriorityQueue, OrderGate, Sequencer, Deduplicator, and RateLimiter) use the same transferable route projection for their destination leg rather than six adapters;
  • membership cores (Router, WorkQueue, Topic, and PubSub) retain the concrete route capability in their ordered state, preserving equality and removal evidence without assuming logical identity. Registry and Resolver intentionally model logical-name bindings and therefore remain logical rather than pretending to be universal endpoint stores;
  • lifecycle owners already use dedicated exact or direct-child capabilities; their remaining gap is truthful availability evidence at the network boundary, not another routing implementation; and
  • pure state cores with no destination leg (Machine, lease state, barriers, latches, and similar folds) compose through layers and typed protocol hops; they need no invented route parameter.

This classification prevents two opposite errors: forcing every template into one recipient representation, and leaving six or more bespoke destination implementations merely because their state laws differ. Route construction is shared; the queueing, ordering, membership, lifecycle, and workflow folds stay separate exactly when they own different transitions.

The expanded black-box layer suite now covers routing, persistence, stashing, both shutdown transformations, absolute and relative timing, periodic and activity-driven timing, logical observation, terminal monitoring, and terminal propagation. It asserts initialization and transition lanes, including a finalization fold whose delivery must survive the outer stop decision. The current cumulative ledger, including untracked tests, is:

production: +193 / -9 / net +184
tests:      +294 / -0 / net +294
docs:       +238 / -0 / net +238
public API: +2 types / -0 types
changed files: 9

This remains below the current thresholds. The next production conversion is catalogue-wide by design and will exceed 15 files once independent models, compile checks, and documentation are included; it remains paused at the required explicit expansion checkpoint.

Universal route projection: expanded pre-edit ledger

The route audit found a more fundamental duplication than the six destination fields. The former DeliveryRoute<P> and DeliveryRouteProtocol expressed one law twice: the former repeated a protocol parameter that the latter already projected as an associated type. Thirty production files mentioned one of these contracts, and 26 repeated DeliveryRoute<P> bounds. Adding another route parameter only to the six forwarding actors would preserve that catalogue-wide duplication and make their concrete types longer.

The next stage therefore converges on one transferable route contract with an associated Protocol and Sends, keeps DeliveryRouteFor<Owner> as only the additional direct-child ownership proof, and removes DeliveryRouteProtocol. Existing reply-route users migrate mechanically to the single projection. Payload-forwarding and truthful membership actors then use the same route law for their destination/member leg. No *Route wrapper, layer configuration type, adapter actor, effect algebra, registry, or dynamic dispatch is added.

Expanded expected surface:

  • 30 existing production files for the contract and every current route-bound catalogue actor, plus the six destination folds and any membership fold whose independent identity test proves logical-only storage is not its law;
  • approximately 10–15 existing model, property, compile, and black-box test files, with both logical and established traces and negative direct-child ownership cases;
  • production target +250 / -300 / net -50 or smaller; the stage must stop independently if net-new production approaches 500 lines;
  • public API +0 types / -1 types by deleting DeliveryRouteProtocol; no new wrapper, alias, builder, marker, or effect product; and
  • existing Delivery, EstablishedDelivery, ChildDelivery, SendEffects, DeliveryOutcomes, and named actor products are reused rather than reimplemented.

Because this intentionally crosses the 15-file threshold, no production edit for this stage is permitted without explicit expanded-surface authorization.

Universal route projection: implementation result

The authorized conversion now has one transferable DeliveryRoute contract with associated Protocol and Sends. Logical and established capabilities implement it directly. DeliveryRouteFor<Owner> adds only the separate proof needed for an owner-local ChildRoute; it does not make that route transferable. Proxy exercises the owner-local law for its real worker child.

Every payload-forwarding and membership core listed above now stores or accepts the concrete route capability and accumulates its concrete send product. A black-box matrix runs all ten actors with established endpoints and checks the actual endpoint, payload, outcome, creation lane, and continuation decision. The logical model/property suites remain unchanged in vocabulary and therefore continue to test the state law independently of the new route implementation.

The associated protocol also made separate Reply/D parameters redundant. They were removed from acknowledgement, circuit-breaker, configuration, correlation, health, lease, presence, readiness, registry, resolver, task, workflow, message-adapter, FIFO-pool, and keyed-pool signatures. Four private phantom aliases were inlined. This is deletion rather than another wrapper or compatibility layer.

The higher-order audit does not justify replacing supervisor or pool correlation with a queue implementation. Proxy owns the unique join between fresh incarnation creation, stop, replacement, shutdown, and typed command return. Fixed and dynamic supervisors own provenance-sensitive proxy/worker fact joins. Pools additionally join assignment identity, completion, returned commands, worker stops, replacement availability, and terminal drain. A separate queue or router can be their child, peer, or supervised payload through ordinary layers and routes, but substituting its fold would split those atomic joins across mailboxes and change the law. The earlier selector-only supervised wrappers were deleted; the retained higher-order actors contain only these correlations plus explicit effect products.

Current cumulative checkpoint, including untracked tests:

production: +1160 / -1058 / net +102
tests:      +833 / -195 / net +638
docs:       +290 / -12 / net +278
public API: +2 types / -1 type

Complete catalogue classification

“Core” means a standalone actor fold. “Transformation” means a wrapper that owns a distinct typed event/effect law. “Composition” means the public use case must be written by nesting or connecting retained concrete actors. A truthful structural alias such as a direct Here form may remain when it names the same template rather than advertising another actor law.

Catalogue surfaceOwned transition lawVerdict
Machinefinite-state receive/become transition and staged drain atomicityretain core
MessageAdapterWithRouteone pure protocol map followed by one typed deliveryretain core
Stashbounded hold/replay order over an inner foldretain transformation
StopOnShutdowndirect shutdown-to-stop event transformationretain transformation
FinalizeOnShutdownshutdown reaction returning complete inner Actionsretain transformation
Guardian, CoordinatedGuardianno state beyond the two shutdown transformations abovedelete; compose the retained transformations directly
Watchrecurring logical-name observation across later incarnationsretain as its own concrete transformation
TerminationMonitor, exact monitor formone correlated observation lifecycle with terminal consumptionretain one monitor implementation with typed target form
EstablishedWatch and watch target policy aliasesrestrict or parameterize the monitor reaction without another lifecycle lawdelete; use the exact monitor and an ordinary reaction
PropagateTerminationone correlated source fact and explicit propagation dispositionretain transformation
Taskpending-to-completed/failed one-result terminal lifecycleretain core
ShutdownCoordinatorordered homogeneous phase shutdownretain transformation
HeterogeneousShutdownCoordinatorordered phase shutdown over a closed heterogeneous effect productretain separately; its typed selection/effect transition is distinct
ChildShutdownPlan, its typestate builder, and shutdown_after_childrenjoins committed direct-child creations, rejects mismatched facts, and reports one typed heterogeneous planretain transformation; generic consumers use associated-output operation traits instead of copying its hidden proof vocabulary
Proxystable slot and fresh-incarnation replacement lifecycleretain core
Superviseadopt application creations into fixed proxy ownership while preserving inner actionsretain transformation
Supervisorstandalone fixed proxy-fleet ownershipretain core, with a concrete implementation rather than a command-policy engine
SupervisedWorkers and selector policy typesparameterize fixed ownership with one routing selectordelete; route commands with an ordinary typed routing actor/application behavior
delayed Supervise policydelays accepted replacement effects from a supervised applicationretain as an explicit timing policy of the same transformation
delayed Supervisor policydelays accepted replacement effects from standalone fixed ownershipretain as an explicit timing policy of the same core
FixedBackoff, BackoffWorkersimplementation/policy parameterizations of the two retained delayed foldsdelete
DynamicSupervisorchanging stable-child membership and replacement lifecycleretain core
WorkerPoolbounded FIFO admission, assignment, completion, and interruptionretain core and its direct Behavior fold
KeyedWorkerPoolthe FIFO law plus persistent key-to-slot affinity and rebalance transitionsretain separately and restore its direct Behavior fold
Deadlineabsolute one-shot schedule and single matching-generation reactionretain transformation
OneShotrelative one-shot schedule and single matching-generation reactionretain transformation
Periodicmatching-generation reaction followed by explicit rearmretain transformation
ReceiveTimeoutactivity-driven generation reset and one notification per idle periodretain transformation
Leaseexclusive ownership, generation-safe expiry, release, and rejectionretain core
Router with its strategiesmembership plus strategy-specific selection/evidence transitionsretain core; strategies are values of this law, not actors
WorkQueuebounded FIFO work plus worker-availability transitionsretain core
Bufferbounded FIFO buffering and overflow ownership policyretain core
PriorityQueuestable immutable-priority admission/releaseretain core
OrderGatemonotonic keyed releaseretain core
Sequencersequence-gap buffering and ordered releaseretain core
Deduplicatorbounded first-seen admissionretain core
RateLimiterexplicit token consumption/refillretain core
CircuitBreakerclosed/open/probing single-flight admissionretain core
Correlatorkeyed request/result ownershipretain core
Acknowledgementsmulti-participant acknowledgement lifecycleretain core
Registrymutable typed binding ownership and lookupretain core
Resolverimmutable definition and read-only resolution capabilityretain core; mutation is unrepresentable in its protocol
Topicone ordered subscription set and snapshot publicationretain core
PubSubkeyed topic introduction, known-empty retention, and per-topic membershipretain core; these keyed states are not actor nesting hidden in a wrapper
Presenceversioned presence evidence and generation-safe expiryretain core
Configurationversioned atomic configuration acceptance/queryretain core
FeatureSeta domain product invariant, not an actorretain product
Features, FeaturesStatename-only aliases of Configuration<FeatureSet<_>>delete; write that concrete composition
Healthversioned component evidence and aggregate healthretain core
Readinessfixed dependency evidence and aggregate readinessretain core
Cachebounded deterministic LRU ownershipretain core
Latchone-generation countdown and single releaseretain core
Barriercyclic fixed-membership generationsretain core
Workflowdependency activation and terminal run lifecycleretain core
composition recipe functionsforward to constructors while inferring structural parametersdelete; construct and nest the concrete types directly

Composition law for the removals

The replacements must preserve complete Actions; they may not intercept, drop, duplicate, reorder, or reinterpret an effect lane. Actor-to-actor composition uses ordinary typed recipients and sends. Wrapper composition uses the retained concrete event layers and named send products. A topology owner, not a generic planner wrapper, remains responsible for correlating its own creation results and reporting any creation-dependent shutdown plan. These are derived Bombay constructions and policy choices, not additional Agha laws.

Implementation checkpoint

The cumulative catalogue rewrite remains production-negative even though the retained pool and shutdown actors now expose their own folds directly. These figures include all tracked and untracked files; documentation is reported separately:

production: +1204 / -2117 / net -913
tests:      +1366 / -581 / net +785
docs:       +331 / -175 / net +156
public API: +5 types / -19 types

Seven forwarding functions are also removed. The three apparent public type additions in the textual diff replace existing aliases with concrete structs of the same name (Watch and Supervisor); they add no public type name. Delayed restart is one policy of Supervisor, not another public wrapper. The five additions were ProxyUnavailable, CommandSupervisionEvent, DeclareShutdownPhase, FinishShutdownPhases, and LogicalHostRequirements; the last was subsequently deleted after the end-to-end audit proved it was assertion-only metadata. Eight constructors or methods were also removed, for 34 removed public names in total. No public wrapper or policy-marker type was added.

The later semantic regressions retain this classification while adding no actor wrapper. Dynamic supervision now joins its two initial creation facts in either order. Proxy commands report complete unavailability through their established parent relationship, and pools join that report with worker-stop/replacement facts. DeclareShutdownPhase and FinishShutdownPhases expose the retained builder to generic consumers through associated outputs. The former logical-host trait did not derive anything from the composed behavior and is not retained as evidence.

Composition-hierarchy tightening

The executable Router → Supervisor-owned Proxy → PriorityQueue → Target hierarchy exposed one remaining false coupling. Router required every destination message to implement Clone because its policy family also contained Broadcast. Consequently a round-robin router could not carry ProxyCommand: its Replace alternative truthfully owns a behavior and is not cloneable.

This was not a proxy or priority-queue defect. The router combined two distinct laws. Bombay now defines Router as single-recipient ownership transfer; RoundRobin, LeastLoaded, ConsistentHash, and RendezvousHash each return at most one membership index. Topic and PubSub retain snapshot fan-out and its explicit payload-cloning bound. The Broadcast policy and the router's multi-index/clone path are deleted. No replacement type or compatibility layer was added.

The black-box regression constructs the real supervisor-staged proxy and the real proxy-staged priority queue, commits the queue creation, then passes offer and release commands through router delivery, proxy child delivery, and queue target/outcome delivery. It asserts every creation, observation, rejection, delivery, and become lane at each boundary. The public composition guide now shows both same-mailbox layers and independent actor topology, including this executable hierarchy.

This tightening stage changes no foundational effect algebra and adds no public type:

production: +48 / -80 / net -32
tests:      +252 / -11 / net +241
docs:       +164 / -5 / net +159
public API: +0 types / -1 type

Alias-free application birth composition: pre-edit ledger

The downstream Bombay audit found one remaining static-composition blocker. Bombay currently requires application-provisioned actors to occupy slots in the domain root's own Behavior::Birth algebra. That makes an item-level root declaration name every fully composed child type before value inference can apply, producing mechanical aliases such as ManagedHealth = StopOnShutdown<Health<...>>.

The actor-model law remains fresh creation. Combining two already-declared creation capabilities is a derived Bombay construction: it must preserve every creator-local nonce, CreationKind, child value, creation-vector position, and pre-existing child occurrence. Application policy—what is provisioned, nonce selection, and initialization order—remains downstream in Bombay.

The smallest end-to-end regression is an inferred application value that adds two differently composed children to a root which already stages its own child. The root creation must remain first, application creations must follow in declaration order, and the root's existing nominal child route must still resolve at its original position. No alias may name either application child or the resulting application type.

Expected stage surface:

changed files: 6-8
production:    approximately +150 / -10
tests:         approximately +200 / -0
docs:          approximately +100 / -0
public API:    +1 trait / -0 types

The implementation must reuse Actions, CreateChild, BirthMode, ChildChoice, ChildProduct, and BirthNodeAt. It must not add a behavior wrapper, layer marker, alias generator, erased child value, runtime registry, or arbitrary creation callback capable of rewriting provenance.

The initial black-box regression failed before the production edit because BirthNodeAppend did not exist. With the static append law present, the same test proves an existing root child role across a lifecycle wrapper and the application composition, while two application child expressions and the complete application type remain inferred. Deterministic tests cover empty left/right identity, associativity, repeated child types at every occurrence, and exact vector order. A 256-case property test preserves every generated nonce, birth/replacement provenance value, lane, and position.

Final stage ledger:

changed files: 7
production:    +170 / -22 / net +148
tests:         +402 / -0 / net +402
docs:          +171 / -0 / net +171
public API:    +1 trait / -0 types

No behavior wrapper, builder, marker, alias, registry, or erased value was added. The one public trait is the closed child-algebra operation needed by a generic composition owner. The private non-empty-node proof only closes its recursive implementation and adds no public name.

Verification

  • cargo check --workspace --all-targets: pass without Rust warnings.
  • Focused birth-composition regressions: 5 passed in debug and optimized builds; the property test ran 256 cases in each build.
  • cargo nextest run --workspace: 527 passed, none skipped.
  • Actor rustdoc and compile-fail tests: 29 passed.
  • The historical supervision_sequences, pool_sequences, and catalogue_sequences targets completed 5,000 fuzz executions each under the locked Fenix input's nightly sanitizer toolchain. Replacement atomic fuzz coverage is catalogued in atomic-actor-verification.md.
  • nix flake check: passes all seven checks, including build, optimized nextest, docs, Rust/TOML formatting, dependency audit, and dependency policy.

Layer-owned parent reporting: pre-edit ledger

Rejected experiment. The implementation following this ledger added a mandatory on_unavailable callback to Supervise::new. Forty-three test and fuzz call sites could satisfy it only with |_, _| Ok(Actions::cont()). That is caller migration driven by the new signature, not evidence of an application-owned transition law. The experiment is quarantined and must be removed; none of its passing compilations count as verification.

The remaining blocker is not construction inference: BehaviorLayer already constructs every concrete output without naming it. The blocker is that the first parent-report redesign made an application event implement EventIngress merely so Supervise could hand an unavailable command back to the application. That exposes interpreter/template routing as application composition work and creates a second user-facing mechanism beside BehaviorLayer.

The smallest regression composes an application with Supervise and an outer shutdown layer, without naming the output, an ingress path, or a composed event type. A proxy-unavailability fact must invoke one explicit application policy, preserve the complete command, and return the policy's complete Actions for ordinary supervision wrapping. The application event algebra must contain only its domain events and must not implement an interpreter-routing trait.

This is a derived Bombay policy: a fixed supervision layer owns proxy reports; the application supplies the pure transition selected for expected command unavailability. Source-indexed event construction remains an interpreter/template proof used to deliver child facts to the owning layer. It does not become an application protocol, another actor effect, or an alternate behavior composition API.

Expected stage surface:

changed files: the supervisor fold, focused layer regression, and direct callers
production:    approximately +20 / -10
tests:         migration-heavy but no new protocol or ingress fixtures
public API:    +0 types / -0 types

The stage reuses BehaviorLayer, SupervisionEvent, ProxyUnavailable, BehaviorActed, and the existing supervisor action wrapping. It adds no wrapper, builder, marker, alias, event variant, effect lane, registry, or erased callback. The unavailability policy is a monomorphized function pointer over the already-concrete application and command types.

Compiler-origin provenance audit

The rejected callback exposed a broader process failure. The current working tree is therefore audited by design provenance before any further compilation or caller migration. Compiler success is not evidence for a public algebra.

The quarantined cluster is:

pathless proxy report
    -> source-indexed EventIngress construction
    -> SupervisionEvent command-unavailability lane
    -> mandatory application callback
    -> 43 no-op test/fuzz policies

Only the final two links are already disproven. EventIngress and pathless parent reports are not accepted or rejected by association; each must still prove a general interpreter/event-composition law through ordinary BehaviorLayer construction, two unrelated templates, two wrapper orders, and a complete end-to-end interpreter trace. If that proof needs an application event variant, explicit wrapper-depth path, supervision-specific handler, or ignored transition, the whole route is removed.

RequestProxyWorker is audited separately. Its candidate law is exact delivery of an owner-created control input to a child occurrence while keeping the child's public domain protocol unchanged. It remains only if a pre-edit regression proves that law without logical hosting, a second proxy protocol, runtime lookup, or application aliases. Downstream compiler demand is not provenance.

No production edit follows from this audit section. The next design stage must first write the desired alias-free BehaviorLayer syntax and complete availability trace as a failing regression. Expected correction is production-negative because the mandatory callback field, constructor argument, transition branch, generic event parameters used only by it, and all placeholder policies are deletion candidates. No new public type is authorized by this audit.

General typed-reaction layer: pre-edit ledger

Rejected as the availability boundary. The focused composition worked, but the first catalogue check showed that it would force every lifecycle-only Supervise<B, C> to add a domain-recovery event even when the composition exposes no domain route. Migrating those callers would reproduce the mandatory-callback defect as a mandatory wrapper. No React production type or migration is retained. The evidence instead locates the missing sum at the proxy boundary: lifecycle ownership and public domain forwarding are currently fused and must become separately composable capabilities.

The user-level syntax under test is:

let behavior = application
    .layer(|inner| React::new(inner, retain_unavailable))
    .layer(|inner| Supervise::new(inner, topology, restart).unwrap())
    .layer(StopOnShutdown::new);

The resulting type is inferred. React is not a supervision policy: it owns the general same-mailbox law “one additional typed input invokes one pure, infallible reaction and preserves its complete Actions; every inner event is delegated unchanged.” Its concrete event sum selects that owned input while retaining the complete inner event algebra. The reaction is infallible because it receives mutable access to the inner behavior; a fallible reaction could mutate and then reject the same event, violating transition atomicity.

For supervised availability, the source is a proxy child report and the input is the complete ProxyUnavailable. Supervise owns only lifecycle correlation: it forwards that input to the already-composed reaction instead of storing an application callback. Startup, replacement, restart exhaustion, and shutdown remain values of the same input law.

Acceptance requires all of the following before catalogue migration:

  • a focused test fails on the prior design because React does not exist;
  • the complete outer StopOnShutdown<Supervise<React<...>>> fold preserves every send, creation, and become lane while recording each unavailable command exactly once;
  • an unrelated typed input and the reverse relevant wrapper order use the same mechanism without supervision-specific bounds or aliases;
  • the mandatory Supervise callback, its field and transition branch, and all 43 placeholder policies are deleted; and
  • at least one existing one-off event-only transformation is deleted or expressed directly by this general law, so the abstraction reduces rather than relocates the catalogue surface.

Expected surface for the design stage:

production files: 4-7
production delta: at most +180 / at least -100
focused tests:    2 files before any catalogue migration
public API:       +2 general types / -1 or more one-off types

The later caller migration will exceed 15 files and is separately authorized by the resumed holistic audit. It may add no further semantic surface.

Typed unavailable route: rejected replacement

Rejected. Adding UnavailableRoute to Supervise merely moved the callback obligation into a public generic and then propagated that generic through delayed supervision. It did not remove a repeated behavior law, and one unrelated outer layer would still force caller edits. The focused route regression and all production edits from this experiment were removed. None of its compiler results count as design evidence.

The reaction experiment proved that application recovery cannot be a required inner transition of every lifecycle composition. The command is instead returned through an explicit customer capability already modeled by DeliveryRoute. Supervise stores that concrete route and emits its concrete send product; it never invokes an application callback and never asks the runtime to host a fabricated protocol at the supervising actor's own address.

The complete same-mailbox product is structural rather than bespoke:

Event = SupervisionEvent<
            EventLayer<ProxyUnavailable<A, C::Msg>, B::Event>
        >

Sends = SendLayer<
            SupervisorSends<A, C>,
            SendLayer<UnavailableRoute::Sends, B::Sends>
        >

Lifecycle facts remain owned by SupervisionEvent. One unavailable command is owned by the existing EventLayer; Supervise converts it to exactly one delivery through the supplied route. Application events and actions remain the innermost lane. The application behavior is not mutated, invoked, or failed by expected unavailability.

Pools and dynamic supervision keep their stronger owner-specific laws. Their proxy reports already return to the owning parent through the typed report path; the pool joins the returned assignment with worker-stop/replacement facts, while dynamic supervision selects the per-child route retained from Start. Neither needs a second logical host at its own address.

The focused regression must fail on the callback design, then prove all four unavailable phases through StopOnShutdown<Supervise<...>>. It asserts the exact destination, complete returned command, every empty lifecycle and application lane, creations, next decision, and that the application fold was not invoked. A separate routing hierarchy must exercise unavailability before the old manually-fed Router → Proxy test can count as evidence.

Expected design-stage surface:

production files: 3-6
production delta: net-negative or at most +80
public API:       +0 types; remove the callback and one event generic/variant

The later constructor migration supplies real typed routes. A placeholder route, fabricated self-recipient, ignored delivery, or route used only to make a test compile invalidates the design.

Ownership inversion: current design checkpoint

The repeated failure is caused by choosing Supervise as the unit of design. Current BehaviorLayer is a static construction and inference contract; it does not turn a hard-coded higher-order fold into semantic composition. Supervise still constructs Proxy<C> internally, so proxy forwarding and availability necessarily leak into supervision, delayed supervision, pools, tests, and downstream application types.

The behavior laws must instead be separated before another signature is proposed:

Law ownerState and correlation it may ownWhat it must not own
stable incarnationone pending fresh installation, current incarnation, replacement provenance, and terminal child shutdowncustomer recovery, restart selection, backlog, or application events
domain availabilityexactly one selected law for every admitted command during installing, running, vacant/exhausted, and shutdown phasesworker creation or supervisor restart policy
supervisionproxy/worker lifecycle facts, restart eligibility/budget, and terminal fleet drainthe worker's domain message, customer route, queue, or persistence operation
delayed supervisiongeneration-safe delay of an already accepted replacement effecta second supervisor state machine or availability policy
poolthe atomic join of job, assignment, completion/return, worker loss, and terminal interruptiona second implementation of proxy incarnation or restart timing

The intended construction must name no resulting behavior type and must not thread an availability type through supervision:

let stable_worker = worker
    .layer(availability(customer_policy))
    .layer(stable_incarnation());

let application = application.layer(supervise(
    topology([slot], |_| stable_worker),
    restart_policy,
));

The names above are domain-level acceptance syntax, not authorized Rust API. An implementation is acceptable only if its concrete layers each own the law listed in the table, the application and higher-order output types remain inferred, and it deletes the mandatory callback, the unavailable-message generic on supervision events, and the hard-coded construction of a forwarding proxy inside supervision. A type added merely to realize this spelling is not accepted.

Before production work resumes, the audit must select the one availability law for the public stable destination and write its full transition table in customer vocabulary. The same table must drive pure-fold tests for startup, running delivery, replacement, restart exhaustion, shutdown, duplicates, and stale lifecycle facts. Only then can the existing incarnation, routing, buffering, acknowledgement, and event/effect products be evaluated as lower-order composition candidates.

Live claim-versus-implementation failures

The following earlier audit statements are currently false and must not be used as completion evidence:

  1. The catalogue says the standalone fixed Supervisor core is retained, but fixed_supervisor.rs is deleted and no Supervisor is exported. Only the application wrapper Supervise<B, C> remains. Fixed fleet ownership without an application fold is therefore no longer a public feature despite the table claiming otherwise.
  2. The higher-order actors are not assembled from an already-composed stable child. FixedFleetOwnership, Supervise, DynamicSupervisor, WorkerPool, and KeyedWorkerPool all name Proxy<C> in their birth, child-route, observation, shutdown, or replacement effects and construct it with Proxy::new internally.
  3. The documented Router -> supervised Proxy -> PriorityQueue witness is a sequence of manually invoked pure folds. Manual transfer can be useful unit evidence, but the test also supplies an ignored unavailable-command callback and exercises only the running phase. It does not prove that the complete outer interpreter stack delivers, returns, or recovers a command during startup, replacement, exhaustion, or shutdown.
  4. The former LogicalHostRequirements was documentation-only metadata. No catalogue behavior implemented it, and its tests exercised only a locally authored dummy product. It has been deleted rather than advertised as a complete transitive requirement.
  5. BehaviorLayer currently abstracts only value construction and associated output inference. It does not by itself compose state, events, actions, births, initialization ordering, or independently running actor configurations. Describing hard-coded higher-order actors as layer-composed because their constructors can appear inside a closure is incorrect.

These failures reopen the catalogue verdict. Production work remains frozen until the replacement design shows both actor-configuration composition and same-mailbox transformation separately, preserves the actual fixed-supervisor feature, and replaces the hard-coded stable child in at least fixed supervision, dynamic supervision, and one pool without propagating a new caller-named type or placeholder policy.

Layer-owned availability: pre-edit ledger

Provisional design rejected after the catalogue check. Requiring every domain message to implement the recovery law makes a framework concern part of the worker protocol and makes a lifecycle-only Never protocol invent an impossible capability. The brief implementation was useful evidence, but is not the general architecture and must not remain as the completion design.

The replacement law belongs to composition:

DirectionAlgebraOwner
mailbox inputclosed sum of the inner user event and each layer's private lifecycle factsthe concrete composed behavior
transition outputnamed product of inner/user sends and every layer's system sendsthe concrete composed behavior
constructionreusable BehaviorLayer from a worker behavior to one stable-child behaviorthe topology owner receives the layer value; callers do not name its output
unavailabilitypolicy owned by the stable-incarnation layerneither the raw domain message nor the supervisor

System creation, observation, stop, replacement, and shutdown values remain framework-owned typed lanes. Application authors do not define or manually union system commands. A supervisor, dynamic supervisor, or pool must consume the already-composed stable-child contract instead of naming Proxy<C> or reimplementing its lanes. User commands need a customer route only when the selected availability policy is an explicit typed return; buffering or capability withholding must not be encoded as a fake route.

The first user-syntax regression is the existing complete hierarchy in behavior-testkit/tests/universal_layers.rs. It now passes the stable-child construction as |worker| worker.layer(Proxy::new) to fixed supervision and names no output type. Against the current production surface it fails for two independent, intended reasons:

  1. Supervise::new accepts only the application, raw-worker topology, and restart configuration, so the stable-child layer is rejected as an extra argument and proxy construction remains hard-coded.
  2. PriorityQueueMessage is rejected for not implementing the provisional ReturnUnavailable trait, proving that the provisional design leaks stable-incarnation policy into an otherwise complete domain protocol.

These are the two production seams the next stage must remove. Adding an implementation of ReturnUnavailable to PriorityQueueMessage, deleting the layer argument, or replacing it with a callback would game the regression.

The actor-model acquaintance law rules out reconstructing a customer from User::from: an origin address is not proof that the origin accepts the worker's command or rejection protocol. The actor model also does not select Bombay's availability policy. A stable-incarnation layer must choose and expose one truthful policy. An explicit customer-return policy needs a real typed customer capability; a parent-recovery policy uses the already-established child/parent relationship and a typed parent ingress; a buffering policy owns its capacity and typed overflow result. None may invent a logical host from an address or require an unrelated domain message to implement framework policy.

The concrete pool use proves the narrow owner contract needed now: when its stable child cannot accept an assignment, the child returns the complete assignment through the existing typed parent-report path, and the pool handles that private input in its own event sum. The runtime already retains the concrete child type and occurrence in LocalParentReports; EventIngress selects the exact parent event lane without a caller-named wrapper path. The same structural rule must work when the child is the output of a BehaviorLayer, rather than being hard-coded as Proxy<C>.

The complete transition table is:

Proxy phase when command is admittedObservable result
Runningexactly one owner-proven child delivery; no unavailable delivery
Dormant, initial Installing, or install during shutdownexactly one policy-owned unavailable effect retaining phase and complete command
AwaitingStop or replacement Installingexactly one policy-owned unavailable effect; never send new work to the stopping or not-yet-committed worker
Vacant, including restart exhaustion/rejectionexactly one policy-owned unavailable effect
ShuttingDownexactly one policy-owned unavailable effect

Wrong, stale, duplicate, and contradictory lifecycle facts remain typed proxy errors and cannot consume or duplicate a command. Shutdown and replacement inputs retain their existing state law. Parent recovery keeps one typed report and ingress path; it removes the fabricated logical host and the mandatory domain-message trait. No callback or absolute wrapper-depth parameter is part of the contract.

User-level construction names no composed output type:

let stable = worker.layer(Proxy::new);

Proxy::new denotes the concrete parent-recovery policy demonstrated by pools. Its mailbox event is the closed sum of the worker's user lane and proxy-owned lifecycle inputs; its sends are the named product of worker delivery and proxy-owned lifecycle/report effects. The application author neither defines those system inputs nor names the composed output type. No command trait, proxy route generic, callback, policy marker, registry, erased envelope, or runtime lookup is introduced.

Expected design-stage surface:

production files: 6-10
production delta: net-negative
public API:       at most +2 general child-input contracts / remove ReturnUnavailable
focused tests:    direct proxy table plus one real pool and one dynamic trace

The general child-input contract, if the existing concrete composition cannot express the regression without it, must replace RequestProxyWorker; it may not coexist as a second delivery mechanism. It must target the concrete layer-produced child and one private input lane, and Bombay must interpret that same type without constructing ProxyEvent<C> itself. Lifecycle-only fixtures use an uninhabited domain protocol; they may not invent a command or empty recovery effect merely to compile.

The compositional gap is the direction of ingress, not replacement itself. ChildInput transfers one private value from an established parent to its direct child. ReportToParent transfers one owned value in the opposite direction and the interpreter attaches the authoritative child nonce. These are different capabilities and must not share one catch-all ingress trait. The child-input contract therefore constructs only the concrete child's private event. A report-owning behavior transformation delegates that contract to its inner behavior structurally; it never names the delegated input. EventIngress remains the parent-side selection law for an incoming child report or same-actor owner input. This is a derived Bombay communication law, not an actor-model primitive.

Narrow pool completion capability: pre-edit ledger

Exact blocker. A worker assignment currently carries a recipient for the pool's complete public protocol. The worker must therefore name the recursive WorkerPoolProtocol or KeyedWorkerPoolProtocol, including the customer reply route, even though it only needs to report one completion. This is not essential protocol information for the worker; it is an ownership leak from the pool actor.

The smallest end-to-end regression constructs a worker whose public message is an assignment containing only job, assignment token, stable slot, and payload. The worker emits one typed completion report. Through the stable-incarnation layer and an outer shutdown layer, the runtime must deliver that report to the pool's private completion event exactly once. The pool must then emit the customer response through its existing reply route. The worker construction must not name the pool protocol, customer reply route, final stable-child type, or a structural parent path.

This is a derived Bombay communication law, not an Agha primitive. The actor model permits communication only through acquired acquaintances; Bombay's creator/child relationship is the acquired structural capability used here. The report remains an ordinary typed send effect in Actions. The interpreter adds the exact creator-local child nonce and injects the resulting child fact into the parent's closed event sum. It performs no lookup and may not silently discard a closed-parent failure.

The proposed reusable laws are:

LawInputOutputState
structural parent reportone owned report valueexactly one parent event containing the exact child nonce and reportnone
stable-child relayone matching direct-child reportexactly one structural report to its own parentnone
pool completionone matching stable-slot reportthe existing completion transition and response effectsexisting pool state only

The pool must also have exactly one lifecycle authority. FixedFleetOwnership owns stable installation, current worker incarnation, replacement admission, restart exhaustion, and terminal drain. A pool slot owns only the work that the pool accepted: vacant, assigned, returned before delivery, or permanently retired with the customer-facing reason. Installing and Stopping are derived observations of ownership and must not be stored again by the pool. No reconciliation transition is permitted.

Authoritative ownership observationPool-owned workPublic pool phase
drainingany active work after it has been returnedStopping
current worker incarnation is routablevacantIdle
current worker incarnation is routableassignedAssigned
no routable incarnation, slot restartablevacant or returnedInstalling
slot permanently retiredretained retirement reasonRetired

Every accepted lifecycle fact is folded by ownership once. The pool may then move an accepted job or retain a customer-facing retirement reason, but it may not infer lifecycle provenance from its own work state. A rejected, duplicate, stale, or contradictory fact leaves both ownership and work unchanged.

The first law must replace the template-specific proxy report interpreter requests; it may not become a parallel reporting mechanism. The relay is a valid same-mailbox layer only because it owns a distinct event/effect transformation. It must delegate unrelated user, lifecycle, initialization, send, birth, error, and become lanes without positional caller knowledge. Duplicates and stale completion facts are still judged by the pool's existing assignment-token law; the relay neither deduplicates nor reinterprets them.

Desired application syntax:

let workers = ChildTopology::new([7], |_| Some(worker));
let pool = WorkerPool::new(workers, configuration, replies, Proxy::new)?;

The worker's assignment and completion types may name real job and result types. They may not name WorkerPoolProtocol, KeyedWorkerPoolProtocol, the customer reply route, Proxy, the pool behavior type, or a wrapper output.

Expected stage surface:

production files: 8-12 in Behavior Actors, plus the Bombay interpreter
production delta: replace specialized reporting; do not retain both paths
public API:       at most 2 general report/child-fact types; remove the three
                  template-specific interpreter-request identities
tests:            pure report/relay folds, complete FIFO and keyed pool traces,
                  outer-wrapper interpreter trace, compile-fail wrong source,
                  and optimized duplicate replay

Dynamic management protocol identity: pre-edit ledger

Exact blocker. DynamicSupervisor currently implements Protocol as the complete behavior type. Adding or changing its stable-child BehaviorLayer therefore forces every unrelated sender to change its delivery type or alias, even though the management message law is unchanged.

The user-level invariant is that a sender names only the dynamic-management domain: address, worker behavior, and the selected customer reply-route kind. The topology owner separately constructs a value with an inferred stable layer. Adding an unrelated worker layer must change neither sender code nor the public protocol identity.

This is a Bombay nominal-capability correction, not a new actor or transition law. One zero-state protocol type replaces DynamicSupervisor<..., L> as the destination identity. It owns no state, fold, policy, builder, or wrapper.

production files: 2-4
production delta: approximately neutral
public API:       +1 nominal protocol; remove the Protocol implementation from
                  the composed behavior type
tests:            two stable layers share one sender protocol; wrong worker or
                  reply outcome remains a compile-time error

Returned-assignment ordering correction: pre-edit ledger

Exact blocker. After the pool emits one assignment, the stable proxy may later report both that its worker stopped and that the still-mailbox-admitted assignment could not be forwarded. The current pool joins these facts only when unavailability arrives first. Worker-stop first moves or resolves the job; the matching later return is then misclassified as UnexpectedAssignmentUnavailable and fails the pool actor.

The actor-model law is only sequential processing of each actor's accepted communications. Message paths and delays do not determine a global arrival order; Karmani and Agha explicitly describe actor message arrival as indeterminate. Bombay therefore may not derive a FIFO guarantee between the worker lifecycle observation and the proxy's returned command. The pool join is a derived Bombay construction, while retry-versus-interrupt remains the existing explicit pool policy.

The smallest regression submits one assignment, folds the matching WorkerStopped first, then folds the exact ProxyUnavailable. It must retain the one accepted job, emit no duplicate response or assignment, and accept the return once. Replaying the same return must preserve the complete fact in the existing typed duplicate/stale error. The complete interpreter regression must execute the same order through StopOnShutdown<WorkerPool<...>> -> RelayChildReports<Proxy<...>>, rather than injecting the pool event directly.

The state law is a product of two independently coexisting facts:

  • current slot work is vacant, assigned, returned-before-stop, or retired; and
  • zero or more exact assignment/job correlations were already retried or customer-resolved while their proxy-return fact may still be in flight.

The second component is not another lifecycle owner and does not retain a job, payload, route, proxy phase, or worker incarnation. It exists only after the pool has resolved the job side of the join. A matching return consumes exactly one correlation; a wrong nonce, wrong assignment, wrong job, duplicate, or unrelated stale return remains the existing complete typed error. Shutdown and restart exhaustion record the same correlation before resolving the customer, so a later authoritative return cannot become an opaque actor failure.

Expected stage surface:

production files: 1
production delta: approximately +30 / -5
public API:       +0 types / -0 types
tests:            the independent pool model and complete outer interpreter
                  hierarchy, in debug and optimized builds

The implementation may add one private correlation product to the existing pool slot. It may not add a behavior wrapper, protocol, route, layer, callback, registry, marker, alias, or second ownership fold.

Transitive logical-delivery projection: pre-edit ledger

Exact blocker. BirthProtocols truthfully projects only the protocols installed by a behavior's transitive birth algebra. Intentional logical Delivery<P> lanes remain visible in each concrete sends product, but there is no structural projection that lets a generic application owner prove it hosts every such P used by the root and every transitive child. The former LogicalHostRequirements let owners manually repeat a list and therefore proved neither completeness nor correspondence with the actual sends tree; it and its gamed dummy test were deleted.

This is static Bombay owner/interpreter metadata, not a new actor effect and not an Agha law. The send algebra already distinguishes logical delivery from established-incarnation delivery, creator-local child delivery, private child input, and interpreter requests. The projection must follow those existing concrete distinctions without inspecting values or changing Actions.

The desired compile-time law is:

logical(Vec<Delivery<P>>)       = P × ∅
logical(established/child/input/request lanes) = ∅
logical(named product)          = append each field projection in interpretation order
logical(Behavior B)             = logical(B::Sends)
                                  ++ logical(each transitive B::Birth child)

The result reuses the existing BirthProtocol<P, Tail> / NoBirthProtocols duplicate-preserving product and its structural append and membership proofs. A repeated protocol in two lanes or two child occurrences therefore remains repeated. A framework may recursively require Hosts<P> for each product element; repeated bounds are lawful and do not require normalizing the product into Bombay's unique runtime host map.

The first regression derives the exact product from an application with one logical root delivery, one exact-only root delivery, and two births of a leaf with the same logical delivery. It contains no manual requirements impl. A second catalogue regression covers ordinary recipient, established recipient, mixed recipient, named send products, wrappers, pools, and transitive worker layers. An unsupported custom sends product must fail at the projection trait, not silently contribute an empty product.

Expected stage surface:

production files: 5-8
production delta: approximately +180 / -20
public API:       +2 consumer traits and +1 doc-hidden birth-node fold;
                  no public data type
tests:            replace the deleted manual-metadata test with structural
                  derivation and add catalogue exact-product assertions

Every existing named sends product will implement the same structural projection in actors::requirements; this avoids spreading metadata through template folds. No behavior wrapper, host value, registry, dyn, Any, TypeId, protocol erasure, macro-only route, callback, or runtime lookup is authorized.

Transitive logical-delivery projection: core/catalogue checkpoint

The implementation follows the stated structural law. Core send leaves and SendLayer implement LogicalDeliveryProtocols; LogicalHostRequirements is blanket-derived from one behavior's sends and every transitive birth node. The actors catalogue implements the same fold for its handwritten semantic products. Unsupported custom send products fail at LogicalDeliveryProtocols rather than silently projecting an empty list.

Evidence is independent of an owner-authored metadata list:

  • the structural test derives P, Q, Q from one root logical lane, one exact lane, and two child occurrences of the same logical destination;
  • a framework-style recursive consumer accepts the duplicate-preserving product without canonicalizing it;
  • real worker-pool and dynamic-supervisor birth trees derive only their actual customer reply protocol; and
  • the compile-fail contract rejects an opaque custom send product.

No behavior wrapper, runtime host value, registry, erased protocol, callback, or manual requirements implementation was added.

The attempted automatic implementation for #[behavior]-generated named products is rejected and removed. It made every declared field require LogicalDeliveryProtocols at actor definition time, so a valid custom effect lane such as Vec<u8> stopped being a valid SendEffects product even when no logical-host projection was requested. Hidden generics, marker traits, and syntax-based macro classification would only move that compiler constraint and are not authorized.

Generated and custom products use the same owner contract as handwritten catalogue products: the product owner implements LogicalDeliveryProtocols when, and only when, a framework asks for complete hosting metadata. This does not narrow Behavior, SendEffects, or custom interpretation. A generated two-delivery product projects both destinations in authored order. A separate custom product containing one delivery lane and one uninterpreted Vec<u8> marker lane projects only its actual delivery. The existing generated Vec<u8>-only products continue to compile without any projection impl.

This is not the deleted manual behavior-level requirements list. The contract is co-located with the concrete sends product whose InterpretSends law gives those fields meaning, and the blanket behavior projection still traverses all root and transitive birth products. As with SendEffects and InterpretSends, a downstream implementation is responsible for satisfying the documented trait law; an arbitrary custom interpreter's semantics cannot be discovered by inspecting Rust syntax.

Compiler-driven relapse checkpoint

The automatic #[behavior] projection was not the only compiler-shaped assumption in this stage. A complete workspace test build exposed two more:

  • the hierarchy regression declared Births<Queue> on an application that never stages a queue creation, then treated the resulting appended ChildChoice<Queue, Proxy<Queue>> as though it were exactly the proxy; and
  • after the fabricated pool completion recipient was removed, the pool constructor no longer receives or derives its customer result and reply-route contract. A later real Submit value still cannot determine R through the non-injective Route::Protocol::Msg equality.

The false birth capability is removed from the test. The complete seven-test layer hierarchy now builds and passes with NoBirths; its sole creation is the stable child actually staged by supervision. No production type was changed to accommodate ChildChoice.

The initial pool inference failure was also classified too quickly as a production blocker. Topology, replacement policy, and the worker layer contain no customer result schema or reply-route kind. BehaviorLayer can infer the complete concrete wrapper stack, but no static construction can truthfully invent public protocol facts absent from both its inputs and its expected context. The owner must state that domain contract somewhere.

An actual command value alone does not provide reverse inference through Route::Protocol::Msg; claiming that it did was incorrect. The application owner instead states the public protocol it hosts:

B::Protocol = WorkerPoolProtocol<MailAddr, Job, Result, ReplyRoute>

That is domain identity, not the concrete composed actor type. From this owner boundary Rust infers the complete WorkerPool<...>, BehaviorLayer::Output, proxy, relay, event sum, sends product, and birth tree. The corrected regression retains the inferred value and executes initialization plus a real PoolMessage; it is not a discarded compile-only witness. It names no composed behavior, recursive worker protocol, parent path, or effect-product alias. A turbofish on WorkerPool, phantom witness, unused recipient, default generic, or constructor overload remains rejected because each would encode compiler evidence instead of the protocol an actor owner must actually host.

The semantic boundary follows the actor model's acquaintance rule: an actor can communicate only through a known name, and names may be communicated in messages. Bombay then adds four derived, statically typed communication forms:

directionemitted effectauthority/provenancerealized input
external or peer to actorDelivery / EstablishedDeliveryknown logical or exact recipientpublic User lane
creator to direct childChildDeliverycommitted creator-local child bindingchild's public User lane
creator to direct childChildInputcommitted binding plus owner-selected private laneprivate child event
direct child to creatorReportToParentestablished creator relationshipChildReport with interpreter-attached child nonce
interpreter back to emitterInterpreterRequest returnrequest's declared local continuationselected event in the same incarnation

The model justifies ChildInput and ReportToParent/ChildReport as distinct effect laws: they travel in opposite directions, use different established relationships, and attach different provenance. ChildInputIngress is the receiver contract for the former; EventIngress selects owner/report or local continuation inputs for the latter cases. The two traits may remain because they correspond to different interpreter capabilities, not because one blanket implementation overlaps another. ReplacementRequested<C> also remains a distinct request value: carrying a behavior definition is not evidence that a replacement was created or installed, and the request must remain distinct from both those later facts.

production edits authorized by this checkpoint: 0
public types authorized by this checkpoint:      0
next evidence: complete workspace build, then catalogue classification of
               remaining public wrappers and hard-coded higher-order laws

Delayed replacement composition: provisional pre-edit ledger

The standalone-supervisor fuzz contract still requires delayed replacement, but the current worktree exposes that law only through BackoffSupervise, whose input is the application-specific Supervise behavior. Restoring a second standalone backoff state machine would duplicate ownership and repeat the compiler-driven design that this audit is removing.

  • Exact blocker: one timer-delay law cannot consume both existing owners, Supervisor and Supervise; the standalone fuzz target therefore cannot express its previously covered behavior.
  • Smallest regression: construct Supervisor::new(..., Proxy::new), apply the same delayed-replacement layer used for Supervise, observe a worker stop, prove no replacement input is emitted before the matching timer, and prove exactly one is emitted after it.
  • Expected files: the shared backoff implementation and exports, its unit and interpretation tests, the standalone fuzz target, and current documentation (fewer than ten files).
  • Expected production delta: net negative, because one generic transformation replaces template-specific backoff products and avoids restoring the deleted standalone implementation.
  • Public types: add one owner/consumer contract and one genuine delayed-law behavior; replace the current backoff send product with its schedule-only lane; remove the application-specific BackoffSupervise surface.
  • Reused law: Supervisor and Supervise remain the sole owners of topology, restart policy, observation, shutdown, and replacement input creation. The delayed layer may only retain and later re-emit those existing replacement inputs; it must not recreate or reinterpret the supervision fold.

Delayed replacement: completed ownership-law checkpoint

The proposed outer delayed layer is rejected. Intercepting an emitted replacement input after the inner ownership fold has advanced would let the owner record a request as issued while the child has not received it. A worker creation fact, shutdown, or another stop arriving during that interval would therefore be folded against a false ownership state. Making the wrapper repair that state would duplicate and reinterpret supervision.

Delay instead participates in the existing replacement-admission sum inside FixedFleetOwnership. RestartTiming::Immediate opens the replacement gate in the admitting transition. RestartTiming::Delayed(Backoff) retains the exact batch and its per-member replacement requests behind one generation-tagged timer gate. Timer arrival and worker readiness join in either order; the last required fact emits each replacement exactly once. Shutdown cancels the retained batch, and stale or duplicate timer facts emit nothing.

This is Bombay policy rather than an actor-model timing guarantee. It adds one policy sum carrying real state and deletes both former BackoffSupervise and BackoffSupervisor behavior families, their wrapper events, send products, errors, parent-path variants, aliases, and duplicated folds. The same private ownership implementation is exercised by standalone Supervisor, application-owned Supervise, and both worker-pool variants.

Independent evidence compares the complete schedule and replacement lanes of standalone and application-owned supervision for the same trace. A pool trace additionally proves that an interrupted assignment stays queued until the exact timer releases replacement, that a duplicate timer cannot release it twice, and that installation dispatches the retained job once.

Standalone failure reaction: pre-edit ledger

Exact blocker: standalone Supervisor::with_failure_reaction accepts Step<Never>. Because that spelling defaults both the phase and terminal payload to Never, callers cannot construct its documented stop result; the configuration can only continue. The supervision sequence target exposes the defect by attempting the advertised terminal reaction.

expected production files: fixed_supervisor.rs
expected production delta: 3 substitutions, net zero
public API: +0 types / -0 types
reused algebra: Become = Step<Never, Stopped>
regression: budget denial returns the complete failure report and Stop(Stopped)

No policy enum, marker, wrapper, alias, or convenience constructor is needed.

The contract now uses the existing Become alias, making both Continue and Stop(Stopped) constructible. The regression proves that budget denial keeps the complete typed failure report while the configured standalone owner selects termination; the supervision sequence target exercises the same path.

Redundant installation-proof facade: pre-edit ledger

Exact blocker: InstallationRequirements, RequirementAt, and four public aliases merely repeat Behavior Core's already-exported BirthProtocols, BirthProtocolAt, BirthProtocol, NoBirthProtocols, and structural position types. They add no state, transition, effect, proof, or inference capability; the actors facade already re-exports the core vocabulary wholesale.

expected production files: requirements.rs, lib.rs
expected production delta: approximately -75 lines
public API: +0 types / -6 types
tests/docs: spell the same exact products with the existing core proof

The logical-delivery projection implementations remain in requirements.rs; only the parallel installation vocabulary is removed.

The six-name facade is deleted. All exact-product, repeated-occurrence, wrapper, proxy, pool, and dynamic-supervisor proofs now use the Behavior Core vocabulary directly; the workspace check passes without a compatibility alias.

Nominal public capability consistency: pre-edit ledger

Exact blocker: Cache, Barrier, and Latch each implement their complete nominal public Protocol for Self, but their Behavior::Protocol is an equivalent MessageProtocol. A sender can therefore name a Recipient<Cache<...>>, Recipient<Barrier<...>>, or Recipient<Latch<...>> that is not the protocol identity the runtime hosts for that behavior. No protocol-adaptation law justifies the second identity.

This is Bombay's derived stable-capability law, not an actor-model guarantee: a standalone catalogue actor that authors one nominal public protocol exposes that exact protocol through Behavior::Protocol; transparent outer layers preserve it.

smallest regression: each actor and StopOnShutdown<actor> satisfies
                     Behavior<Protocol = actor> and accepts an ordinary
                     Recipient<actor> capability
expected production files: cache.rs, barrier.rs, latch.rs
expected production delta: 3 substitutions, net zero
public API: +0 types / -0 types
reused algebra: the existing Protocol impl for Self and transparent wrapper law

The regression must fail on the prior definitions because the protocol identities differ, not because a helper alias is missing. No alias, wrapper, conversion, compatibility implementation, or constructor is authorized.

The pre-fix regression produced six E0271 identity failures: one for each standalone actor and one for each transparent shutdown composition. The three behaviors now expose Self; ordinary nominal capabilities and the wrapped forms compile and pass in debug and optimized builds. No transition branch, message, effect, error, or constructor changed.

production: +8 / -9 / net -1
tests:      +31 / -0 / net +31
public API: +0 types / -0 types

Keyed-pool delegation: pre-edit ledger

Exact blocker: KeyedWorkerPool owns only key-to-stable-slot binding, first-admission selection, and explicit rebalance, but it stores the private PoolState and repeats the ordinary pool's complete lifecycle, completion, returned-assignment, shutdown, and dispatch transition. Sharing the state helper is not behavior composition; the two public folds can drift while claiming one pool law.

The keyed actor remains a distinct transformation because its affinity table is genuine state. It must store and delegate to the existing concrete WorkerPool, handling only keyed submit and rebalance itself. Common events must enter the ordinary pool fold exactly once; its complete actions pass through unchanged and its uninhabited-key error is widened exhaustively by the existing widen_pool_failure function.

smallest conservation trace: FIFO and one-key pools receive equivalent
                             initialization, installation, submit, completion,
                             worker-stop, replacement, shutdown, duplicate,
                             and stale facts; common action/error snapshots
                             remain equal
expected production files: pool.rs only
expected production delta: net negative (delete the repeated common match)
public API: +0 types / -0 types
reused laws: WorkerPool Behavior fold, KeyedWorkerPool affinity sum,
             widen_pool_failure, identical PoolSends and Births products

This is a deletion/refactor claim, not a new observable actor law. A black-box test cannot distinguish two identical implementations from delegation; source deletion is the evidence for composition, while the independent and exhaustive keyed/FIFO models protect observational conservation. No structural proof marker, constructor overload, wrapper, policy trait, or source-text test is authorized merely to make the old implementation fail a test.

Keyed-pool delegation: completed checkpoint

KeyedWorkerPool now stores the concrete WorkerPool behavior. Keyed submit and rebalance remain its only authored transitions. Initialization and every common completion, returned-command, creation, stop, timer, and shutdown event enter the ordinary pool fold exactly once. The one shared private subfold is targeted admission: the keyed layer needs its Accepted | Rejected result to commit a new affinity binding atomically, and that result is not an effect that may truthfully be recovered by inspecting Actions.

No public declaration, wrapper, alias, constructor, event, or effect product was added. The FIFO and keyed independent models pass in debug and optimized builds; the complete outer-layer interpreter tests pass in both profiles; and the pool sequence fuzz target completed 5,000 runs. Workspace Clippy is clean.

The cumulative working-tree checkpoint after this stage is:

production:     +3762 / -3753 / net +9
tests:          +4251 / -2300 / net +1951
docs:           +1599 / -70   / net +1529
infrastructure: +28   / -2    / net +26

Pool effect product: pre-edit ledger

Exact blocker: the pool owns three semantic effect lanes—customer responses, worker assignments, and fleet supervision—but its complete effect product is a private SendLayer<SupervisorSends, PoolBehaviorSends>. Direct users and interpreters must consequently know that pool effects are .inner and supervision effects are .owned; another transparent wrapper adds another positional hop. The paths describe implementation nesting rather than the pool contract.

This is Bombay's named-product law. Replace the existing public PoolBehaviorSends with one public PoolSends product whose fields are responses, assignments, and supervision. It must preserve the current interpretation order—responses, then assignments, then supervision—and preserve the current return-to-emitter paths. It must append each lane once and project only the logical response destinations. This is a replacement, not an additional layer.

smallest regression: construct PoolSends by semantic field name and interpret
                     one value in every lane; assert the complete ordered trace
expected production files: pool.rs, requirements.rs, lib.rs
expected test/docs files: runtime_contracts.rs, pool model/property/fuzz users,
                          worker-pool.md
expected production delta: approximately net zero
public API: +1 product / -1 product
deleted machinery: private PoolSends alias and the pool's SendLayer nesting
reused laws: SupervisorSends, SendEffects, SendsFor, InterpretSends,
             LogicalDeliveryProtocols, existing concrete pool events

No wrapper, builder, alias, marker, conversion, compatibility spelling, or generic lane registry is authorized.

Pool effect product: completed checkpoint

PoolBehaviorSends and the private SendLayer alias are gone. PoolSends now owns the complete named product: responses, assignments, and supervision. Its SendsFor proof keeps customer effects at the inner pool event path and supervision requests at the outer supervision path. Its interpreter visits responses, assignments, and supervision once each in the previously authored order. Logical-host projection remains exactly the customer response protocols; creator-local assignments and interpreter-owned supervision requests do not fabricate hosts.

The pre-fix compile regression failed because PoolSends was not public. The complete interpreter regression now constructs every semantic lane by name and observes the exact eight-effect trace in both debug and optimized builds. FIFO and keyed independent/model suites, wrapper-order tests, and user-facing pool construction tests pass in both profiles. Workspace check and Clippy are clean.

A neighbouring test incorrectly expected the supervision law to observe an inner behavior's unrelated child creation. The production fold already preserved the correct boundary. The strengthened test now proves that the inner creation remains the prefix birth occurrence and precedes the two owned stable creations, while only the stable topology is observed.

This stage is not code reduction: the explicit named-product implementation is 18 net new production lines after deleting the generic nesting.

stage production: +53 / -35 / net +18
stage tests:      +78 / -85 / net -7
stage public API: +1 product / -1 product

cumulative production:     +3815 / -3788 / net +27
cumulative tests:          +4329 / -2385 / net +1944
cumulative docs:           +1665 / -73   / net +1592
cumulative infrastructure: +28   / -2    / net +26

Supervision-test semantic correction checkpoint

The complete workspace run exposed seven tests whose expected traces described a different ownership law from the production types:

  • several strategy/model tests stopped workers before their authoritative creation facts had installed them, then expected unresolved peers to emit replacements immediately; and
  • two tests treated unrelated inner-application births as though Supervise had adopted them into its fixed fleet.

No production fold was changed. The corrected tests first join every declared stable child with its committed creation fact, then exercise replacement strategy over that installed topology. Inner births are asserted to remain the preserved prefix of the composed birth algebra and outside fixed ownership. The replacement trace now also proves that RestForOne follows declared topology order rather than numeric nonce order.

The corrected focused suites pass in debug and optimized profiles. The full workspace then passes 542 of 542 tests and workspace Clippy is warning-clean. This checkpoint also removes the now-unused dynamic-birth fixture; it adds no production code or public API.

cumulative production:     +3822 / -3802 / net +20
cumulative tests:          +4358 / -2486 / net +1872
cumulative docs:           +1697 / -67   / net +1630
cumulative infrastructure: +28   / -2    / net +26
public API: replacements and deletions recorded by the per-stage ledgers;
            no public type was added by this checkpoint

Unconsumed transition effects: pre-edit ledger

Exact blocker. Actions is the explicit, still-uninterpreted result of one actor transition, but the value type is not must_use. The workspace denies unused_must_use, yet a test or interpreter can unwrap a successful fold and silently discard its sends, fresh creations, and next-behavior verdict. The current tree contains direct examples, including lifecycle and wrapper tests. This defeats the audit rule that tests observe complete actions and leaves the compiler lint unable to enforce the underlying semantic law.

This is a derived Bombay effect-conservation rule: producing Actions is not performing those effects. A caller must interpret, inspect, or explicitly retain the complete value. Marking the existing product must_use adds no effect, state, route, wrapper, or type.

smallest regression: a successful Active::transition(...).unwrap(); statement
                     is rejected by the workspace unused_must_use lint
expected production files: effects/actions.rs only
expected production delta: +1 attribute, net +1
expected test files: the initial textual scan found fourteen; the diagnostic
                     contract exposed at least thirty-one source/unit files
                     before downstream testkit binaries compiled, so the final
                     inventory is the warning-clean full workspace
public API: +0 types / -0 types; one diagnostic attribute on Actions
repair law: each site asserts or feeds the complete sends, creations, and
            become verdict appropriate to its independent model

Binding a result to an underscore, calling drop, or locally allowing the lint is not an accepted repair. The test must state why every effect lane is empty or otherwise consume its complete observable result.

The stage exceeds fifteen files. This is inside the already-authorized repository-wide audit, but the expansion is recorded rather than hidden: the single production attribute revealed previously existing test evidence loss; it did not cause or require another production abstraction.

Heterogeneous shutdown effect visibility

The unconsumed-effect regression exposed one independent testability defect: HeterogeneousShutdownSends<T> is public, but its sole semantic lane is private and the only slice accessor is compiled for crate unit tests. A framework consumer can interpret the product, but cannot inspect or model-check the complete transition result as data. That contradicts the named-product law used by the other public effect products.

smallest regression: an integration test cannot name the emitted ordered
                     shutdown selections in Actions.sends.owned
expected production files: lifecycle/shutdown_coordinator.rs
expected production delta: replace one test-only accessor with one public,
                           documented read-only accessor; approximately +3 net
expected test files: heterogeneous_shutdown.rs
public API: +0 types / -0 types; +1 read-only method
reused law: the existing HeterogeneousShutdownSends product and its exact
            phase-ordered request vector

This does not add a planner, layer, wrapper, route, or alternate effect lane.

Unconsumed transition effects: completed checkpoint

Actions is now must_use. Every diagnostic exposed by the workspace was repaired by observing or forwarding the complete result rather than binding it to _, dropping it, or suppressing the lint. The public heterogeneous shutdown product now exposes its existing ordered lane through a read-only as_slice method, so integration and model tests can inspect the complete effect without privileged test-only access.

The independent fuzz workspace now also denies unused_must_use. Its twelve targets consume initialization and transition actions, including sends, creations, and the next-behavior verdict. Each target completed 5,000 generated runs after the discovered minimal sequences were replayed directly. The runs corrected several copied or incomplete test assumptions: application births are not adopted into fixed ownership, presence announcement always replies, pool stop may both replace and assign in one action, and initial proxy creation requests observation before the worker-resolution join completes. These are test-oracle corrections; no production behavior was changed to satisfy a fuzz branch.

The generated corpus and crash files were removed after replay. They are run artifacts, not source evidence. The flake now exposes a locked fuzz package and shell containing nightly Rust, llvm-tools-preview, and cargo-fuzz, while the ordinary repository gate remains on pinned stable Rust. A clean consumer can therefore build or run the same targets with nix run .#fuzz -- ... without relying on a separately installed mutable toolchain.

stage production: +12 / -0 / net +12
  Actions attribute: +1
  existing heterogeneous shutdown lane accessor: +11
stage public API: +0 types / -0 types; +1 read-only method
fuzz source/infrastructure currently visible in the working-tree diff:
  +826 / -299 / net +527

Exact dynamic-start capability: pre-edit ledger

Exact blocker. A successful dynamic start currently receives an authoritative committed creation fact and then returns Recipient::global(address). That discards incarnation identity and reconstructs a weaker logical destination from allocation data. The Started outcome must carry the exact established recipient produced by the creation commit. A rejected creation must carry no recipient.

This is the existing creation-capability law, not a new dynamic-supervision abstraction. Reuse ObserveEstablishedCreation, EstablishedCreation, and EstablishedRecipient; do not add a wrapper, conversion registry, second protocol, or address-to-endpoint lookup.

smallest regression: both initial-fact orders return the exact endpoint issued
                     by the creation interpreter, exactly once
expected production files: dynamic_supervisor.rs and requirements.rs
expected production delta: approximately neutral
expected test files: dynamic_supervisor_join.rs, runtime_contracts.rs,
                     supervision_sequences.rs, and affected interpretation tests
public API: +0 types / -0 types; Started strengthens its existing child field

Exact dynamic-start capability: completed checkpoint

DynamicSupervisorOutcome::Started now returns the exact EstablishedRecipient issued by the committed proxy creation fact. The fold retains that capability when it arrives first, joins it with the matching worker-resolution fact in either order, and emits it exactly once. Rejections carry no capability. Wrong nonces, wrong creation kinds, duplicate facts, stale facts, and contradictory authoritative results retain their complete typed errors; shutdown is total before, between, and after the joined facts.

The complete outer StopOnShutdown<DynamicSupervisor<...>> composition is tested in both fact orders. The independent join suite passes six cases in debug and optimized builds, and the supervision fuzz target completed 5,000 runs through both orders, worker rejection, and all intermediate shutdown points using the flake-locked fuzz runner. The generated corpus was removed after the run.

No public type, wrapper, registry, protocol alias, or endpoint lookup was added. Existing logical-address tests now use test-local runtime address types with opaque established endpoints where they model dynamic creation; fixed supervision and pool contracts remain logical where no exact establishment law applies.

production files: dynamic_supervisor.rs and requirements.rs
public API: +0 types / -0 types
verification: workspace compile; focused debug/release folds; 5,000 fuzz runs

Explicit restart timing: pre-edit ledger

Exact blocker. RestartConfiguration::new and PoolConfiguration::new silently choose RestartTiming::Immediate. Immediate versus delayed emission changes the transition trace and is therefore policy, not a constructor default. Construction must receive the timing value explicitly. The delayed convenience constructors then carry no distinct law and should be deleted rather than retained as a second configuration path.

The mechanical caller migration spans more than fifteen files (the current search finds 85 constructor occurrences across production, tests, benches, fuzz targets, and documentation). No production edit for this stage begins without treating that breadth as the required checkpoint rather than hiding it behind an alias or compatibility constructor.

expected production files: supervisor.rs and pool.rs, plus direct production callers
expected production delta: net-negative
expected public API: +0 types; remove `RestartConfiguration::delayed` and
                     `PoolConfiguration::delayed`
reused law: RestartTiming and the existing immediate/delayed ownership fold

Explicit restart timing: completed checkpoint

Both configuration products now have one constructor, and that constructor requires RestartTiming. Seventy-seven formerly implicit immediate choices and seven delayed-constructor choices were migrated directly; no default, alias, wrapper, or compatibility path remains. The existing immediate and delayed ownership folds remain the only semantic implementations.

The focused public-contract regression and the independent supervision and pool models pass in debug and optimized builds. All 542 workspace tests, the warning-denied Clippy and rustdoc gates, and the authoritative Nix flake check pass. The supervision and pool fuzz targets each complete 5,000 runs without a crash; their generated untracked corpus expansions are removed afterward.

production: +4893 / -4183 / net +710
tests:      +7403 / -2964 / net +4439
docs:       +2043 / -107 / net +1936
infra:      +52 / -2 / net +50
public API: +37 types / -53 types; this stage adds no type and removes two
            redundant public constructor methods

Public relay classification

RelayChildReports is not compiler-only naming machinery. It owns one observable transformation: one report from one statically selected direct child becomes exactly one ReportToParent effect, while every inner event, effect, birth, error, phase, and verdict is preserved. The pool uses that law to move worker completion across the proxy edge without fabricating a logical destination.

That justifies a concrete reusable composition in actors::composition; it does not automatically justify placing the type and its event algebra in the crate-root application facade. The export audit must distinguish the public associated-type requirement from root-level convenience and remove the latter if no direct application use requires it.

Completion cleanup audit: evidence checkpoint

The cleanup pass distinguishes unreachable code from public-but-unnecessary facade exposure and from concrete types that must remain nameable through a public Behavior associated type.

Current evidence:

  • workspace Clippy passes for all targets and features with warnings denied;
  • every Rust source below crates/behavior/src and crates/actors/src is reachable from the current module graph; the deleted backoff-supervisor file has no remaining module or source reference;
  • the working tree contains no untracked fuzz corpus or crash artifact;
  • a source scan before each #[cfg(test)] module finds no production Recipient::global(...) construction; and
  • current documentation no longer names ProxyCommand::Forward or describes dynamic Started as a reconstructed logical recipient. Released changelog sections retain their historical names as release history.

The warning-denied rustdoc gate exposed two source-documentation defects: Registry linked to Delivery without a resolvable path, and public Supervisor documentation linked to the crate-private FixedFleetOwnership type. The links are repaired without widening the ownership fold.

FixedFleetOwnership, OwnershipFold, and OwnershipError are crate-private and retained. The first owns the one shared fixed-fleet state-transition law; the second is the named product of complete actions plus an optional failure that the application-composed, standalone, and pool owners interpret differently; the third retains complete rejected lifecycle facts for those public error mappings. The former WorkerDisposition and WorkerOwnershipFold names no longer exist.

RelayChildReports and RelayChildReportEvent must remain public inside actors::composition: the concrete relay is both directly composable and appears through the pool's public birth/event algebra. Its unused crate-root re-export is removed; that deletes a duplicate spelling without removing the relay feature.

EventIngress and ChildInputIngress are not classified as dead. They currently name opposite established-parent directions: child-to-parent facts enter the parent's event algebra, while private parent-to-child inputs enter the concrete child's event algebra. However, the relay also relies on the trait split to combine one owned report implementation with blanket preservation of arbitrary inner child inputs. Before accepting that as two laws, a separate pure/compile-only probe must establish whether one existing owner-indexed ingress contract can express both directions without structural paths, overlap, a new marker type, or a wrapper. Compiler coherence alone is not sufficient justification under the layer laws.

The downstream Bombay tree confirms that no compatibility surface should be restored here: its current migration branch still names removed parent-specific composition types and asserts that Started.child has a logical address. It already owns exact endpoint interpretation, so it must consume the strengthened established capability and update its application test rather than Behavior reintroducing a weaker alias or address reconstruction.

Behavior Actors template-law audit (engineering record)

Historical evidence snapshot: the retained campaign verdicts were last committed at 1f20cc4. They describe that revision. The current repository quality audit tracks later verification and unresolved work.

This is the working record of a proof-driven audit of every reusable Behavior implementation exported by bombay-behavior-actors. It replaces the earlier routing-only review, which incorrectly accepted creator-local delivery from a standalone MessageAdapter and did not test BehaviorBase at the runtime resolution boundary.

This file is not a completion certificate. A verdict is final only after its negative cases have an independent oracle and the full repository gates pass on the recorded revision. Earlier versions of this file incorrectly declared the catalogue complete while several action-loss and hard-coded-path cases were still untested; those declarations are not evidence.

Active owner-contract follow-up ledger

This checkpoint records the four independently reported gaps before any production edit. It is not evidence that any gap is closed.

  • Exact blockers and smallest regressions:
    1. A generic framework can declare and finish shutdown phases through associated outputs, but cannot begin the one existing inferred builder without naming its hidden initial proof. A compile-only external-consumer regression must call a generic begin operation, declare two roles, and finish without spelling builder states.
    2. RelayChildReports forwards nested ingress but drops root ShutdownRequested ingress. Pure-fold regressions must cover the relay, FIFO pool, keyed pool, and relay under another transparent composition; the report lane must remain exactly once.
    3. Supervise retains worker installation and replacement facts but exposes no typed evidence to its inner application. An independent lifecycle trace must observe initial readiness with the exact worker nonce, replacement start/unavailability, replacement readiness, and permanent retirement or restart denial without guessing elapsed time.
    4. WorkerPool::new and KeyedWorkerPool::new cannot infer the customer route because no input mentions it. External-user compile tests must compare an associated construction operation, a route witness, and an extension operation, rejecting any dummy value that the pool does not semantically retain.
  • Source classification: serialized actor turns, fresh creation, and the absence of a cross-producer arrival-order guarantee are actor-model laws. Root-ingress preservation and the associated-output builder entry are derived static compositions. Lifecycle evidence after a committed ownership transition, its exact fact vocabulary, and restart timing are explicit Bombay policy rather than Agha guarantees.
  • Expected files: shutdown builder/re-exports and its interpretation test; report relay plus relay/pool composition tests; supervision protocol, ownership fold, adapter and model/fuzz tests; pool constructors and one external construction test; this audit record. Expected cumulative ceiling: 15 changed files.
  • Expected production delta: at most +260 / -40 / net +220. Tests and documentation are measured separately at each checkpoint.
  • Expected public API: add at most three public items: one begin operation, one exhaustive lifecycle fact sum (with data carried in its variants), and one owner-defined pool construction operation only if existing inherent syntax cannot express the inference law. Add no wrapper, alias, builder, route marker, registry, or erased envelope. Remove any superseded public machinery discovered in the same semantic path rather than retaining a compatibility layer.
  • Existing machinery to reuse: shutdown_after_children and its sole ChildShutdownPhases typestate; InjectEvent/ComposedEvent and the relay's named SendLayer; FixedFleetOwnership, OwnershipFold, and SupervisionEvent; DeliveryRoute, Recipient, BehaviorLayer, and the existing FIFO/keyed pool folds. No parallel planner, lifecycle wrapper, or pool factory object is permitted.
  • Toolchain finding: the repository pins Rust 1.95. General type-position ! remains unavailable on that toolchain and on stable 1.98; stabilizing it remains an active Rust 2026 project goal. The existing uninhabited Never remains the MSRV-compatible representation. Neither Never nor ! can constrain a customer route generic that occurs in no constructor input.

Supervision lifecycle design checkpoint

The application-facing lifecycle is one exhaustive event sum, not a wrapper, callback, query API, or second supervisor. One authoritative runtime fact may produce at most one inner lifecycle event. Multi-slot restart policy is carried as one named batch variant so the inner application performs at most one fold per outer turn.

Lifecycle eventData owned by the variantLegal source transition
Readystable proxy nonce, exact worker-incarnation nonce, explicit CreationKindthe join becomes complete after either a successful proxy creation or a successful worker creation; a replacement kind identifies replacement readiness
ReplacementStartedcomplete triggering WorkerStopped, exact running-worker creation facts selected by one-for-all/rest-for-one, and stable nonces selected while still awaiting initial creationone atomic restart admission succeeds; delayed admission is still unavailable and cannot become ready before its matching replacement creation commits
RetiredAfterStopcomplete WorkerStoppedrestart policy deliberately declines replacement
Retiredcomplete existing SupervisionFailurerestart admission, worker factory, worker creation, proxy creation, or stable-proxy continuity fails permanently
ShuttingDownall stable slot nonces whose availability is endingthe first accepted shutdown request; duplicate shutdown requests produce no second lifecycle event

The Ready join is symmetric: worker-first retains the worker fact without notifying, proxy-first retains the proxy fact without notifying, and the matching second success emits exactly one event. Duplicate, stale, wrong-kind, wrong-nonce, and contradictory facts remain the existing typed errors and emit no lifecycle event.

Lifecycle delivery must be an ordinary variant in the inner application's named exhaustive domain/system event sum. That sum owns EventIngress<Here, SupervisionLifecycle<A>>; existing structural EventLayer compositions lift the source-indexed ingress to it without a caller naming or recounting wrapper depth. Supervise must not make the lane optional, silently discard it, invoke a callback, or queue an interpreter-private self-message. Applications needing no lifecycle evidence use the standalone Supervisor topology owner instead.

Controlled-error atomicity requires a prepare/commit transition:

  1. validate the authoritative fact against the current ownership sum;
  2. prepare the next ownership state, effects, and one lifecycle event without mutating ownership (restart admission is calculated on a staged budget and newly built workers remain owned by the plan);
  3. fold the lifecycle event through the inner application;
  4. only after that fold succeeds, commit the prepared ownership state and combine the complete inner and ownership Actions products once.

If the inner fold rejects the lifecycle event, the prepared workers are dropped and neither the restart budget nor ownership state commits. This preserves B7 rather than relying on actor termination to hide partial mutation. For lifecycle-free authoritative facts, the existing ownership transition is unchanged.

Making this lane truthful is intentionally source-breaking: every current Supervise inner event that lacks the lane must be migrated explicitly. A scan finds 20 source/test/fuzz call-site files in addition to the supervision protocol, ownership fold, and adapter. With the nine files already changed in this follow-up, the complete migration necessarily exceeds the 15-file review checkpoint; compatibility modes would only evade that checkpoint while preserving the broken contract.

The audit question is not merely whether a template's fold compiles. For every capability or lifecycle fact, the review traces:

  1. who produced or supplied it;
  2. which concrete type retains it;
  3. which actor namespace owns its interpretation;
  4. which Actions lane emits it;
  5. which static interpreter authority realizes it; and
  6. how rejection or stale input remains typed and observable.

Laws and policies used

The source classification matters. Framework convention is not presented as actor-model law.

Actor-model laws

  • A1 — serialized turns: one actor processes one communication at a time; the transition determines communications, fresh creation, and the next behavior.
  • A2 — finite acquaintance: a transition may communicate with prior acquaintances, acquaintances in the current communication, and freshly created actors.
  • A3 — fresh creation: allocation is fresh; replacing behavior with become is distinct from actor creation.
  • A4 — no primitive effect ordering: the actor model does not require a general order among send, create, and become effects.

The primary-source classification and the exact boundary between these laws and Bombay constructions are summarized in the canonical actor-transition algebra and established-capabilities contracts.

Behavior Core laws

  • B1 — explicit effects: a successful pure fold returns complete Actions; it does not deliver, allocate, schedule, observe, or stop actors through an ambient side channel.
  • B2 — concrete protocols: protocol, event sum, send product, phase, error, and birth algebra remain statically visible.
  • B3 — capability distinctions: Recipient, ChildRoute, and EstablishedRecipient mean logical name, creator-local occurrence, and exact installed incarnation respectively. They are not interchangeable.
  • B4 — structural child authority: a local child effect resolves only when the running emitter's direct Birth algebra proves the named occurrence.
  • B5 — transparent projection: nominal roles cross BehaviorBase only while both canonical protocol and complete direct-birth algebra are equal.
  • B6 — compositional initialization: wrappers initialize their inner fold once, preserve its full result, and define how wrapper effects accumulate.
  • B7 — typed rejection: rejected creation carries no established capability; controlled transition failures do not partially commit a new behavior state.

Declared Bombay policy

  • P1 — staged child routes: a creator-local nonce may name a requested child before interpretation but is neither an address nor freshness proof.
  • P2 — commit before dependency: interpreters commit same-action creation before dependent local sends and observation requests.
  • P3 — explicit provenance: birth, replacement incarnation, observation relationship, timer generation, and shutdown request provenance travel as typed data.
  • P4 — structural return paths: interpreter facts return through the exact typed path selected by the owning composition.
  • P5 — explicit root shutdown: the root is composed directly as StopOnShutdown, FinalizeOnShutdown, or a shutdown coordinator; it does not discover a nested shutdown handler.
  • P6 — stable logical domains: discovery membership, configured downstream destinations, stable proxy identity, and transport names deliberately remain logical recipients.
  • P7 — truthful customer routes: a template that accepts an arbitrary customer capability retains its logical or exact form and emits the matching concrete effect without conversion.
  • P8 — creation-dependent shutdown plans: a coordinator may begin before its committed children are known. The topology owner reports its validated plan through Actions to an explicit parent return path; installation is one typed event, happens at most once, and retains any earlier shutdown request.

Hypotheses and verdicts

Failed → fixed means the hypothesis was false in the audited revision and this change repairs it. A pass means both the public type surface and the relevant fold/interpreter seam support the statement.

IDSourceFalsifiable hypothesisVerdict and evidence
H01A1, B1Every template transition is a deterministic fold returning all effects in Actions.Failed → fixed. Machine committed a prefix of a failed drain, Stash could replay a fallible inner fold after earlier actions became unreturnable, and Supervise could reject child adoption after the application fold succeeded. Machine now stages the complete drain, Stash statically requires an infallible inner fold, and adoption is an explicit reported outcome that preserves the rest of the application's Actions. Independent models compare state and complete outputs after every generated step.
H02B2Every exported behavior has concrete event, send, phase, error, and birth types.Pass. All Behavior implementations use associated concrete types; no catch-all envelope or registry exists.
H03B2No template uses dyn, Any, TypeId, downcasting, unsafe, serialization, or type-name dispatch for protocol composition.Pass. Static source scan is clean; the only type_name use is a test assertion.
H04B5, B6A topology-transparent wrapper preserves its inner BehaviorBase, protocol, birth algebra, initialization effects, and order.Pass. Stash, timing wrappers, watch/monitor, shutdown wrappers, and termination propagation project the inner base; equality constraints guard nominal role resolution. Composition and initialization tests exercise nested orders.
H05B4, B5Each standalone behavior that authors a direct topology exposes itself as BehaviorBase<Base = Self>.Failed → fixed. Proxy, WorkerPool, and KeyedWorkerPool lacked the projection. runtime_contracts::every_topology_owner_exposes_itself_as_its_behavior_base now proves proxy, fixed, dynamic, FIFO, and keyed owners.
H06B4, B5A topology-changing composition cannot inherit an inner nominal child role whose birth algebra it replaced.Pass. ResolveChildOccurrence requires exact protocol and birth equality. Supervise may expose its application base for inspection, but its proxy birth rewrite prevents stale role resolution; raw structural positions resolve against the running wrapper.
H07B4, P1Every production ChildDelivery, ObserveChild, ObserveCreation, ShutdownChild, or ChildTermination emitter owns the matching direct occurrence in its Birth.Pass after H05. All such emissions are confined to proxy/supervision/pool/lifecycle owners with the corresponding child leaf; occurrence propagation is tested through nested wrappers.
H08B3, B4A standalone MessageAdapter with NoBirths cannot emit creator-local child delivery.Failed → fixed. DeliveryRoute no longer accepts ChildRoute; a compile-fail example rejects the foreign route before runtime. The adapter retains logical, established, and closed mixed delivery modes only.
H09A2, B3, P6, P7Every delivery destination is supplied by configuration, a received message, discovery membership, or stable-proxy policy—not fabricated from child correlation.Pass. Customer-bearing routing, workflow, operations, persistence, pool, supervision, and discovery messages retain their supplied DeliveryRoute; stable internal logical destinations remain explicit Recipient values. A committed dynamic proxy is returned as the exact EstablishedRecipient issued by the creation interpreter; no logical destination is reconstructed from its child correlation nonce or allocation address.
H10B3, P7A received or configured exact endpoint is never weakened to a logical recipient before delivery, observation, or shutdown.Pass. Exact modes retain EstablishedRecipient/EstablishedActor and emit EstablishedDelivery, ObserveEstablished, or ShutdownEstablished; ReplyRoute retains mixed alternatives and its interpreter visits them in original order. No exact-to-logical conversion exists.
H11B7, P3A rejected EstablishedCreation cannot produce a recipient, actor, child route, birth, or restart-success fact.Pass. The rejected variant owns only nonce, kind, and CreationRejection; independent established-creation models cover allocation through binding failure.
H12B3, B4, P1After a named child commits, callers can retain both its exact incarnation and its creator-local role/nonce without reconstructing either.Failed → fixed. established_child now returns EstablishedChild<C, Role>, a named product of ChildRoute and EstablishedActor; rejection yields neither. Its shutdown_target method selects a heterogeneous plan branch from the retained role.
H13B4, P3Child observation and shutdown preserve the declared occurrence when equal child protocols appear more than once.Pass. All local lifecycle request types carry Occurrence; compile-fail tests reject head/tail or nominal-role substitution.
H14B2, B4A shutdown plan accepts only child behaviors whose exact event algebra owns ShutdownRequested.Pass. Homogeneous and heterogeneous coordinator compile-fail tests reject non-shutdown-capable children; request interpretation uses the resolved concrete child.
H15B4, P4Proxy reports retain the final parent event path through an outer shutdown transformation for every proxy-owning template.Failed → fixed. The reporting path is generic. Action-interpreted outer-StopOnShutdown tests execute creation and stop reports for application-owned supervision, standalone fixed supervision, both delayed forms, dynamic supervision, FIFO pools, and keyed pools. None supplies a structural path at the composition call.
H16B2, P4Every timer, observation, creation, shutdown, and parent-report request names the exact structural return path accepted by the enclosing event sum.Pass. runtime_contracts proves request/fact duals and nested path injection; send-product interpretation tests exercise each lane at the same path exactly once.
H17B6, P5Root shutdown can reach a FinalizeOnShutdown, retaining its final sends, creations, and stop result.Pass. The finalizer or coordinator is placed directly at the root; algebra tests prove delivery to the finalizer and full action preservation. No guardian alias selects that policy indirectly.
H18B3, P3Recurring logical watch and exact-once correlated monitoring remain distinct laws.Historical selected Watch evidence remains separate: it emits ObservePeer and accepts matching logical stop facts, including later incarnations. The new established-target affine-scope correlation, exact protocol-indexed accepted identity and cancellation authority are proposed and unexecuted here; they do not inherit that historical Pass. The candidate TerminationMonitor owns the single requested/observing/terminal control sum and emits one whole ObserveEstablished. Full new owning/consumer evidence and independent review are still required.
H19B3, B7, P3Termination monitoring represents requested, observing, rejected/cancelled, observed, and already-consumed relationships without correlated flags.The public TerminationObservation view derives from one target-owned control sum. Rejected cancellation remains nonterminal and consumingly recoverable alongside Stopped; startup rejection remains distinct. Candidate ownership, replay, both-order and full-report tests must pass before acceptance is recorded.
H20B3, B4Termination propagation chooses either an occurrence-aware local child or an explicitly late-bound logical peer, never an inferred destination.Pass. ChildTermination<A, O> and PeerTermination<A> are distinct target types with distinct request effects.
H21A3, B7, P3Supervision distinguishes replacement request, installation attempt, committed incarnation, rejection, stale result, and retirement.Pass. Incarnation and ownership folds use exhaustive phase enums and explicit creation kinds; independent supervision models and exhaustive/property suites compare the full sequence behavior.
H22A3, P3Restarted or replacement success is reported only after a replacement-designated creation commits.Pass. Proxy reports a request separately, checks CreationKind::Replacement, and emits committed resolution only after installation success; failure remains typed.
H23B7, P3Stale and duplicate lifecycle/timer facts cannot be reinterpreted as fresh success or consume another relationship.Failed → fixed. Timer reactions are now statically infallible, so a matching generation has one total consume-and-react transition. A later audit found consumption hidden inside debug_assert!, which made deadline, one-shot, periodic, and receive-timeout accept duplicates in optimized builds. Acceptance now validates and consumes in the production guard; the redundant preflight helpers were removed. Duplicate lifecycle facts are returned through exact typed errors; stale timer facts remain inert. Debug and optimized regressions, wrapper-order properties, and stack fuzzing exercise these cases.
H24B1, B2Named multi-lane send products preserve every lane exactly once and in their documented structural order.Pass. Each product has explicit SendEffects, SendsFor, and InterpretSends; runtime-contract and cross-lane tests record complete traces.
H25A2, B3, P6A dynamic supervisor exposes the exact committed stable proxy, never a reconstructed logical destination or the replaceable worker incarnation.Failed → fixed. Proxy and worker creation facts are retained and joined in either arrival order. Exactly one Started is produced only after both have committed. It returns the EstablishedRecipient<C::Protocol> issued by the proxy-creation commit; later worker replacement stays local to that proxy.
H26B1, P3Time is always a typed input or schedule request; no fold reads wall-clock time or sleeps.Pass. Production transitions consume Instant carried by lifecycle facts or TimerElapsed, and emit ScheduleAt/ScheduleAfter; Instant::now occurrences are test setup.
H27B2Semantic alternatives entering transition logic are sums, not booleans.Failed → fixed. Circuit-breaker Succeeded/Failed messages were collapsed into succeeded: bool; the private Completion::{Succeeded, Failed} sum now preserves the domain through the helper boundary. Query predicates remain ordinary booleans.
H28B2, B7Option<T> denotes one value or absence, not overlapping lifecycle phases or correlated capabilities.Pass after targeted inspection. Dynamic child, proxy incarnation, pool slot, breaker, lease, workflow, watch, and monitor phases use enums. Remaining options are exact absence queries, optional independent metadata, or optional one-effect outputs.
H29B1, B6Wrapper reactions cannot drop inner sends or creations when selecting Goto or Stop.Pass. Wrappers transform the complete action product with map_sends/named reconstruction; terminal and initialization tests assert retained creates, sends, and verdicts.
H30A3, P1No actor address or exact endpoint is derived from nonce arithmetic, sequence position, timing, or address reuse.Pass. From<u64> in fleet code creates configured local nonces only; exact addresses enter exclusively through interpreter facts.
H31B7Invalid configuration, overlap, exhaustion, unknown targets, and interpreter rejection remain typed results rather than production panics.Failed → fixed. The conservation pass found errors that named only a key, nonce, or reason while consuming the remaining owned input. Machine, router policies, circuit breaker, rate limiter, priority queue, sequencer, lease, acknowledgements, correlation, task, barrier, workflow, health, readiness, presence, registry, pub-sub, supervision, and pools now return the complete rejected command or lifecycle fact. The only production expect is the proved positive capacity + full buffer => oldest value exists invariant.
H32A4, B6, P2Any ordering relied upon beyond actor-model law is declared as Bombay policy and tested at the interpreter boundary.Pass. Create-before-dependent-send/request and wrapper initialization order are documented as policy; send products define their own deterministic interpretation order without claiming it as an Agha guarantee.
H33B2, B3, P7Every genuine customer-passing template accepts logical, exact, or deliberately mixed reply capabilities without allowing the route protocol to disagree with the reply message.Failed → fixed. Customer, payload, and membership fields now carry one Route: DeliveryRoute that projects its exact protocol and send product; the duplicate protocol marker and repeated reply protocol parameters are removed. A catalogue compile/fold matrix instantiates every affected family with EstablishedRecipient and ReplyRoute, protocol mismatch is compile-fail, and logical recursive protocol tests remain finite.
H34B1–B3, B7, P4, P8Homogeneous and heterogeneous shutdown coordinators can receive their validated plans after committed child creation without out-of-band mutation, flags, plan substitution, lost early shutdown, or repeated installation.Failed → fixed. ShutdownState is the complete lifecycle sum. A topology owner emits ReportShutdownPlan through Actions; the interpreter constructs the exact outer InstallShutdownPlan<P> event from the carried typed return path. Unit, independent model/property, fuzz, and compile-fail coverage exercise both plan families, duplicate installation, early shutdown, stale stops, ordered phases, and empty-plan termination.
H35B2–B4, B7, P1, P3A standalone fixed supervisor owns only supervision, while application command selection is expressed by ordinary typed actor composition.Failed → fixed. The former SupervisedWorkers policy engine combined fixed ownership with a selector but owned no distinct lifecycle law. It and its availability-policy surface were removed. Supervisor now implements the concrete fixed-fleet fold directly; an application behavior or routing actor owns command selection and its own typed rejection law.
H36B1–B4, B6–B7, P1–P4, P8Creation-dependent shutdown planning retains a single typed implementation that both direct applications and generic frameworks can carry.Failed → fixed. ChildShutdownPlan owns the distinct join from committed direct-child creation facts to one reported heterogeneous plan. Its direct builder remains the semantic implementation. DeclareShutdownPhase and FinishShutdownPhases expose only associated output types, so a framework neither names nor copies the hidden availability and phase proofs.
H37B1–B2, B6–B7A reusable actor template is retained only when it owns a distinct state-transition or typed event/effect transformation law.Failed → fixed. Guardian aliases, established-watch policy aliases, feature aliases, selector-policy supervisors, backoff parameterization wrappers, and recipe functions were removed. The child shutdown planner remains because it owns creation-fact correlation and plan reporting. Watch and exact-once monitoring, application and standalone backoff, FIFO and keyed pools, and homogeneous and heterogeneous coordinators remain separate because their recurrence, input, assignment, or typed effect transitions differ.
H38B1–B4, B6–B7, P3Expected supervised-command unavailability is observable after mailbox admission and never collapses into an opaque actor crash.Failed → fixed. Proxy returns the complete sender, phase, and command through its established parent-report lane in every unavailable phase. FIFO pools join that return with worker-stop in both orders, including restart exhaustion and shutdown. DynamicSupervisor returns it through the retained Start outcome route, while Supervise routes it into an explicitly authored application-domain event only when that application owns a stable-child route. All three owner paths are interpreted through an outer shutdown composition; the pool join, dynamic customer route, application event, duplicate replay, restart exhaustion, and shutdown cases pass in debug and optimized builds.
H39B1–B2, P1–P4A generic consumer can carry the child-shutdown builder without naming hidden typestate or implementing a second planner.Failed → fixed. Generic full-interpreter tests declare and finish phases using only the two associated-output operation traits; direct syntax, reverse order, early shutdown, and all existing typed failures retain the same builder implementation.
H40B1–B2, P1–P3A composition owner exposes every transitive intentional logical protocol host statically, preserving duplicate occurrences and excluding exact-only endpoints.Failed → fixed. LogicalHostRequirements is blanket-derived from the concrete root sends product and every transitive birth node. LogicalDeliveryProtocols follows each real send-product interpretation order: logical deliveries and interpreter requests with logical recipients contribute their protocols, while established and creator-local routes contribute none. The structural regression derives P, Q, Q without owner metadata; focused request regressions distinguish customer, logical diagnostic, and exact diagnostic routes. No registry, erased envelope, normalization, or runtime lookup was added.

The repairs require no new Behavior Core algebra, runtime registry, dynamic type, forwarding actor, or address reconstruction. The verification record below is authoritative only when every listed gate is green on the same tree.

Complete template coverage

The hypotheses above were applied to every exported behavior family, not just the templates implicated by the initial blockers.

FamilyBehavior templates auditedPrincipal hypotheses
Base compositionMachine, MessageAdapter, MessageAdapterWithRouteH01–H03, H08–H10, H24, H27–H31
Transparent state/lifecycle wrappersStash, StopOnShutdown, FinalizeOnShutdown, Watch, TerminationMonitorWith, PropagateTerminationH04, H06, H13, H16–H20, H23–H24, H29
Shutdown ownershipShutdownCoordinator, HeterogeneousShutdownCoordinatorH07, H12–H17, H23–H24, H29–H32, H34, H36–H37
Lifecycle taskTaskH01–H03, H09–H10, H24, H27–H31, H33
SupervisionProxy, application-composed Supervise, standalone Supervisor, and DynamicSupervisor; delayed replacement is the shared RestartTiming policy inside fixed ownershipH05–H07, H10, H13, H15–H16, H21–H25, H28–H33, H35, H37
Worker poolsWorkerPool and the affinity-owning KeyedWorkerPool, both using the same fixed-ownership and stable-child layersH05, H07, H09–H10, H13, H15–H16, H21–H24, H28–H31, H33
TimingDeadline, OneShot, Periodic, ReceiveTimeout, LeaseH01–H04, H10, H16, H23–H24, H26, H28–H33
RoutingRouter with all strategies, WorkQueue, Buffer, PriorityQueue, OrderGate, Sequencer, Deduplicator, RateLimiter, CircuitBreaker, Correlator, AcknowledgementsH01–H03, H09–H10, H23–H24, H27–H31, H33
DiscoveryRegistry, Resolver, Topic, PubSub, PresenceH01–H03, H09–H10, H16, H23–H24, H26–H31, H33
WorkflowLatch, Barrier, WorkflowH01–H03, H09–H10, H23–H24, H27–H31, H33
Operations/persistenceConfiguration<FeatureSet<_>>, Health, Readiness, CacheH01–H03, H09–H10, H23–H24, H27–H31, H33, H37

Routing strategies are policy values owned by Router, not actors with their own effect boundary. Redundant aliases for the same observation and shutdown state machines were removed rather than counted as separate templates.

Adversarial law coverage

The audit does not count a constructor smoke test as proof of a state-machine law. The following independent suites model state after every generated step:

SurfaceIndependent or adversarial evidence
Creation and exact capabilitiescreation, custody, child_creation_actor, creation_settlement_custody
Machine and replayfsm_properties, exhaustive, fsm_sequences
Stash and wrapper lane isolationstash_properties, two_buffer, cross_lane, stack_sequences
Watch, monitoring, and terminal propagationexact_termination_model, terminal_outcome_sequences, catalogue_sequences
Stable proxy, fixed supervision, and dynamic supervisionstable_proxy_shutdown_model, fixed_supervisor_initialization, dynamic
FIFO and keyed worker poolsfifo_pool, keyed_pool, direct_pool_customer, direct_worker_shutdown, fifo_pool_sequences
Homogeneous and heterogeneous shutdownshutdown_model, heterogeneous_shutdown, shutdown_plan_sequences, plus coordinator compile-fail and ordering tests
Versioned operations and cachecatalogue_invariants models configuration, feature-set normalization, readiness, health tombstones, and LRU ownership
Routing and correlationcatalogue_models, routing_invariants, and correlation_invariants model stable priority, bounded ownership, token arithmetic, round robin, FIFO worker availability, sequencing, deduplication, ordering, correlation, and acknowledgements
Timereceive_timeout, timing_invariants, receive_timeout_sequences; timer-wrapper composition and initialization are attacked by init_contract, cross_lane, and stack_sequences
Workflowworkflow_invariants models barrier generations, latch single release, dependency activation, and terminal rejection; catalogue_sequences fuzzes workflow inputs
Discoveryregistry and topic generated models live in catalogue_invariants; presence is generation-fuzzed by catalogue_sequences; resolver and keyed publication retain focused atomic owner tests because their immutable/snapshot state spaces are already exhaustively covered there

Each model uses different vocabulary and ordinary collections. It compares observable state and complete owned outputs after every operation, including rejection and stale input. Fuzz targets are retained as a separate layer; they do not replace the reference models.

Verification checkpoint — 2026-08-27 working tree

  • cargo nextest run --workspace --no-fail-fast: 542 passed, none skipped.
  • cargo clippy --workspace --all-targets: pass without Rust warnings.
  • The nominal-protocol, pool named-product, keyed/FIFO model, and corrected supervision regressions pass in both debug and optimized profiles.
  • The pool state-machine fuzz target completed 5,000 executions after keyed delegation.

This is an intermediate checkpoint, not the final repository gate. The final record must be updated only after cargo nextest run --workspace and nix flake check pass on the same committed tree.

Capability conclusions

The three recipient forms have non-overlapping authority:

CapabilityMeaningLawful use in templates
Recipient<P>Logical protocol namecaller reply, discovery membership, transport name, or stable proxy identity
ChildRoute<C, O>One role and nonce in the current creator's namespaceonly a topology owner whose direct Birth proves O
EstablishedRecipient<P> / EstablishedActor<C>One exact installed incarnationexact delivery, observation, shutdown, or retained post-creation capability
ReplyRoute<P>Closed logical-or-exact customer capabilityone running template intentionally accepts both forms without conversion

EstablishedChild<C, O> intentionally retains the latter two facts together. It is an Actors-level named product over existing capabilities. It neither allocates an actor nor extends the Behavior algebra.

Future changes must repeat the six-step provenance trace above. A test that only inspects the emitted value is insufficient for creator-local effects: the running emitter must also prove that its interpreter can lawfully resolve the same occurrence.