Problem
An AllForOneStrategy restart snapshots every child regardless of state, including a sibling that is already terminating. That sibling is then handed a recreate, and onRecreate unconditionally resumes its mailbox and sets its state back to running — after its own children have already been sent terminate.
The result is an actor that is running again but whose onChildTerminated will now bail, because the guard there expects state terminating. It has a child set it can never finalise, so it can never terminate.
Evidence
The snapshot takes every child, unfiltered:
src/internal/ActorCell.ts:1143-1145
const affected = strategy.scope === 'all-for-one'
? Array.from(this._children.values())
: [child];
onRecreate then resumes and re-runs it, with no check on the prior state:
src/internal/ActorCell.ts:942-946
this.behaviorStack = [(m: TMessage) => next.onReceive(m)];
await next.postRestart(cause);
this.mailbox.resume();
this.state = 'running';
and onChildTerminated (src/internal/ActorCell.ts:1195) returns early when the state is no longer terminating, so the pending child terminations never complete the parent's own teardown.
Proposal
Filter the all-for-one snapshot to children in a restartable state (running / suspended), and make onRecreate refuse to resume a cell that is terminating or terminated — a restart directive arriving for an actor that is already on its way out should be dropped, not honoured.
Acceptance sketch
Verification status
Found in the ten-lens production-readiness review of 2026-08-05 (v0.13.0) and re-verified before filing: confirmed by reading the three cited sites. Not reproduced at runtime — constructing the interleaving reliably needs a deterministic scheduler, which is itself one of the gaps this batch records.
Part of the production-readiness review batch — tracked in #913.
Problem
An
AllForOneStrategyrestart snapshots every child regardless of state, including a sibling that is already terminating. That sibling is then handed arecreate, andonRecreateunconditionally resumes its mailbox and sets its state back torunning— after its own children have already been sentterminate.The result is an actor that is running again but whose
onChildTerminatedwill now bail, because the guard there expects stateterminating. It has a child set it can never finalise, so it can never terminate.Evidence
The snapshot takes every child, unfiltered:
onRecreatethen resumes and re-runs it, with no check on the prior state:and
onChildTerminated(src/internal/ActorCell.ts:1195) returns early when the state is no longerterminating, so the pending child terminations never complete the parent's own teardown.Proposal
Filter the
all-for-onesnapshot to children in a restartable state (running/suspended), and makeonRecreaterefuse to resume a cell that isterminatingorterminated— a restart directive arriving for an actor that is already on its way out should be dropped, not honoured.Acceptance sketch
all-for-onerestart does not sendrecreateto a terminating sibling.onRecreateon a terminating cell is a no-op rather than a resume.AllForOneStrategy—AllForOneStrategycurrently has no behavioural test at all (see the sibling test-coverage issue in this batch).Verification status
Found in the ten-lens production-readiness review of 2026-08-05 (
v0.13.0) and re-verified before filing: confirmed by reading the three cited sites. Not reproduced at runtime — constructing the interleaving reliably needs a deterministic scheduler, which is itself one of the gaps this batch records.Part of the production-readiness review batch — tracked in #913.