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

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.