@@ -22,10 +22,10 @@ declared:
2222
23231 . Domain schemas used by state and event fields.
24242 . Tagged schemas for states that own data.
25- 3 . Tagged public-event, internal-event, and emitted-event schemas.
25+ 3 . Tagged public-event, internal-event, parent-event, and emitted-event schemas.
26264 . ` Machine.defineStates ` .
27- 5 . ` Machine.make ` , including input, events, internal events, emits, and the
28- initial function.
27+ 5 . ` Machine.make ` , including input, ` events ` , ` internalEvents ` , ` parentEvents ` ,
28+ ` emittedEvents ` , and the initial function.
29296 . One or more ` .handle(...) ` calls.
30307 . Child descriptors.
31318 . Runtime, Atom, or Cluster adapters.
@@ -80,17 +80,18 @@ the deferred constructors preserve that identity after decoding.
8080 a handler.
8181- Every declared output schema needs a matching handler implementation before
8282 planning or execution.
83- - ` parents ` keys are full dotted paths.
83+ - Handler ` ancestors ` keys are full dotted paths.
8484- Invoke lifetimes follow state entry and exit, not the spelling of the target
8585 builder.
8686- Handle every typed invoked Effect failure with ` onFailure ` . Defects and
8787 interruption terminate the owning machine.
8888- Reuse an exported child descriptor for inline invocation, ` sendTo ` , and child
8989 lookup. Independently constructed descriptors are equivalent only when both
9090 their id and machine identity match.
91- - ` events ` is the public input protocol. ` internalEvents ` contains machine-local
92- deliveries such as raised events and invoked-child emissions. Handlers see
93- both; typed public ` send ` and ` Machine.plan ` accept only ` events ` .
91+ - ` events ` is the public actor-input protocol. ` internalEvents ` contains
92+ machine-local raised events. ` parentEvents ` describes the public events a
93+ child may send to its owner. ` emittedEvents ` describes outward ephemeral
94+ notifications and is never delivered implicitly to a parent.
9495- Event tags in ` events ` and ` internalEvents ` must be disjoint.
9596- Event tags must also be unique within each protocol list.
9697
@@ -156,8 +157,8 @@ States.get(snapshot, "Form") // type error: no value schema
156157
157158For a schema-less path, builders expose only ` .from(...) ` ; the direct callable
158159form is reserved for already-decoded schema values. Structural ancestors are
159- also omitted from ` parents ` ; an immediate structural parent is typed as
160- ` undefined ` . Add ` schema ` when a state begins to own data or needs runtime
160+ also omitted from ` ancestors ` ; an immediate structural containing state is
161+ typed as ` undefined ` . Add ` schema ` when a state begins to own data or needs runtime
161162validation and persistence for that data.
162163
163164Use an atomic state when no child phase can be active beneath it.
@@ -380,7 +381,7 @@ parallel builders still require a callback selecting their active child or
380381every active region. Omitted input is normalized to ` {} ` and still passes
381382through ` schema.makeEffect ` , including refinements.
382383
383- ## Reading state and parents
384+ ## Reading state and structural ancestors
384385
385386` Machine.defineStates ` returns typed helpers:
386387
@@ -402,16 +403,18 @@ States.matches(ready, "Route.Ready.Saving")
402403
403404All paths are checked against the definition. ` get ` and ` getWithParents ` accept
404405only schema-backed paths; use ` matches ` or ` getSnapshot ` for any active path.
405- ` context.parent ` is the immediate typed parent value (` undefined ` at a root or
406- when that parent is schema-less). ` parents ` contains only valued ancestors. Use
407- its full paths when another ancestor value is needed:
406+ ` context.containingState ` is the immediate typed state value (` undefined ` at a
407+ root or when that state is schema-less). ` context.ancestors ` contains only
408+ valued structural ancestors. This is separate from ` context.parent ` , which is
409+ the owning actor reference or ` undefined ` for a root actor. Use full state paths
410+ when another ancestor value is needed:
408411
409412``` ts
410- parents [" Route.Ready" ]
411- parents [" Route.Ready.Editing" ]
413+ ancestors [" Route.Ready" ]
414+ ancestors [" Route.Ready.Editing" ]
412415```
413416
414- Do not guess short properties such as ` parents .Ready` .
417+ Do not guess short properties such as ` ancestors .Ready` .
415418
416419### Inspecting the full transition configuration
417420
@@ -473,11 +476,72 @@ Closed statechart and actor operations use `enqueue`:
473476
474477``` ts
475478Submit : ({ target }, enqueue ) => {
476- enqueue .emit (new SaveRequested ({} ))
479+ enqueue .emit (Emissions . SaveRequested ())
477480 return target .local .Saving .from ()
478481}
479482```
480483
484+ Declare emission constructors separately from actor inputs:
485+
486+ ``` ts
487+ const Emissions = Machine .emittedEvents (SaveRequested , AuditRecorded )
488+
489+ const definition = Machine .make ({
490+ events: Commands ,
491+ internalEvents: InternalEvents ,
492+ emittedEvents: Emissions ,
493+ // ...
494+ })
495+ ```
496+
497+ ` enqueue.raise(...) ` is a same-macrostep input to self. ` enqueue.sendTo(...) `
498+ targets an actor mailbox and is processed later. ` enqueue.emit(...) ` is neither:
499+ it publishes a one-off outward notification. Observe it with
500+ ` ref.emissions ` , a hot non-replayed ` Stream ` that completes with the actor.
501+ ` ref.changes ` is stateful and begins with the current lifecycle snapshot.
502+ Startup emissions occur before ` Machine.start ` returns and therefore are not
503+ visible through the returned ref; use state for facts that must be retained.
504+
505+ For child-to-parent input, export a public builder protocol and reuse it at both
506+ composition boundaries:
507+
508+ ``` ts
509+ export const ParentEvents = Machine .events (ChildFinished )
510+
511+ const child = Machine .make ({
512+ events: ChildEvents ,
513+ parentEvents: ParentEvents ,
514+ // ...
515+ }).handle ({
516+ Working: {
517+ on: {
518+ Finish : ({ parent }, enqueue ) => {
519+ if (parent !== undefined ) {
520+ enqueue .sendTo (parent , ParentEvents .ChildFinished ())
521+ }
522+ }
523+ }
524+ }
525+ })
526+
527+ const parent = Machine .make ({
528+ events: Machine .events (ParentCommands , ParentEvents ),
529+ // ...
530+ })
531+ ```
532+
533+ Invoking the child under a parent that lacks any required ` parentEvents ` case
534+ is a type error. Within child handlers, ` parent ` accepts only that protocol.
535+ The same child may run as a root, where ` parent ` is ` undefined ` . ` self ` accepts
536+ the machine's public inputs. Neither actor reference is a structural state
537+ value; use ` containingState ` and ` ancestors ` for statechart ancestry.
538+
539+ Atom-backed actors retain the same transient semantics. Use
540+ ` AtomMachine.emissions(machineAtom) ` for a root and
541+ ` AtomMachine.childEmissions(childAtom) ` for the currently active child. Both
542+ return streams requiring the corresponding ` AtomRegistry ` ; emissions are not
543+ stored as atom state.
544+
481545For asynchronous validation or persistence, invoke an Effect or child machine
482546from the state and handle its typed success or failure event in a later
483547transition. This keeps ` (state, event) => [nextState, commands] ` synchronous.
@@ -551,8 +615,9 @@ type AnyHandledEvent = Machine.Machine.Event<typeof definition>
551615
552616` MachineRef .send ` , ` machineAtom .send ` , and ` Machine .plan ` accept decoded public
553617events or constructions returned by ` Machine .events ` . Transition handlers
554- receive only decoded events. Raised events and child emissions additionally
555- accept constructions from ` Machine .internalEvents ` . The
618+ receive only decoded events. Raised events additionally accept constructions
619+ from ` Machine .internalEvents ` ; outward notifications accept constructions from
620+ ` Machine .emittedEvents ` . The
556621local planner and runtime intentionally share the complete decoder to support
557622those internal deliveries, so JavaScript or ` any ` can bypass the local public
558623distinction.
@@ -582,11 +647,11 @@ self-interrupts fails the parent. `onDone` is required when the output is not
582647are forbidden when their channel is ` never ` .
583648
584649The source may also be a function of the owning state's entry context when it
585- needs ` state ` , ` parent ` , ` parents ` , or the entry ` event ` . Source construction
650+ needs ` state ` , ` containingState ` , ` ancestors ` , or the entry ` event ` . Source construction
586651errors, defects, and interruption are machine failures rather than a second
587652phase in ` onFailure ` .
588653
589- When a source function reads ` state ` , ` parent ` , ` parents ` , or the entry ` event ` ,
654+ When a source function reads ` state ` , ` containingState ` , ` ancestors ` , or the entry ` event ` ,
590655` Machine .invoke ` infers that owner context and the returned Effect's output,
591656error, and service channels together. No return annotation is needed:
592657
@@ -955,13 +1020,19 @@ Wrap the initial builder result:
9551020initial : () => States .initial .Idle .from ()
9561021```
9571022
958- ### Invoked child emits events not accepted by the parent
1023+ ### Invoked child expects events not accepted by the parent
9591024
960- Create an internal descriptor from the child's emitted schemas:
1025+ Export one parent-event protocol from the child boundary and compose it into
1026+ the parent's public events:
9611027
9621028``` ts
963- events : Machine .events (Submit ),
964- internalEvents : Machine .internalEvents (... ChildMachine .emits )
1029+ export const ChildParentEvents = Machine .events (ChildFinished )
1030+
1031+ // child
1032+ parentEvents : ChildParentEvents
1033+
1034+ // parent
1035+ events : Machine .events (Submit , ChildParentEvents )
9651036```
9661037
9671038### An internal event is rejected by ` send `
@@ -996,10 +1067,10 @@ handlers own behavior.
9961067
9971068### Parent property does not exist
9981069
999- Use its full path:
1070+ Use the structural ancestor's full path:
10001071
10011072``` ts
1002- parents [" Route.Ready" ]
1073+ ancestors [" Route.Ready" ]
10031074```
10041075
10051076### Child descriptor types are unrelated
0 commit comments