A recursive node is not the process currently running it. The node is a durable child incarnation; the process is only one temporary owner charged with enacting that authority.
Commit identity before enactment
When a parent macrostep adds a child, the commit records the child slot and its Birth intent before the engine starts or contacts the child. That committed material already determines the exact incarnation:
- the parent entity type and InstanceId;
- the child chart, authored site, and member key;
- the generation allocated by the parent step;
- the current attempt; and
- the derived child Ref and InstanceId.
For a recursive child, the immutable Birth also appends one ancestry frame carrying the recursive group id. The resulting depth and identity do not depend on which host, fiber, or runner enacts the child after commit.
Checkpoint + reenactment + exact identity
A process may restart without the child restarting.
Follow one recursive WorkNode child from committed Birth through runner loss and exact recovery.
1 · Commit the incarnation
The durable parent names one exact child before anything runs.
The parent commits its child slot and Birth intent together. The key, generation, Ref, attempt, input, and ancestry now identify one incarnation independently from the process that will enact it.
2 · Lose the process
A stopped runner removes liveness, not durable identity.
The live owner disappears. The committed parent head, child activation, immutable Birth, and child checkpoint remain. No Statechart step occurs merely because a process stopped.
3 · Recover exactly
Resume reenacts the retained child; it does not create another one.
A new runner decodes the checkpoint, validates exact child coverage, and arms the same key, generation, Ref, and attempt. Arm admission happens again, while Birth and commit counts do not move.
A checkpoint is more than a Snapshot
The committed checkpoint contains the authoritative Snapshot together with the exact activations required to resume it. Every non-completed child slot must have exactly one matching child activation. That activation retains the child site, key, generation, Ref, running or retrying state, attempt, original arming step, provenance, and retry journal.
This is why recovery does not need to infer live work from the active state configuration. The configuration says where the model is. The retained activation says which exact external citizen must be enacted there.
An omitted, duplicated, reordered, or mismatched activation fails checkpoint validation. Motive does not rebuild an approximate child from its chart name and key.
Re-enact, do not rebirth
When a new runner first acquires the instance, the engine decodes the stored checkpoint through the
registered chart's ResumePlan. Resume validates exact coverage, publishes no new Statechart step,
and calls the ordinary child-arm enactment with the retained child.
That second arm admission is intentional. Enactment is retryable because durable authority came
first. In a clustered engine, the already-committed outbox may deliver the same Birth again; the
child accepts matching immutable birth facts idempotently. A conflicting input, origin, or Resource
delegation is an InputMismatch, not another incarnation of the same child id.
The recovery invariant is therefore precise:
recovered.generation === committed.generation;
recovered.ref === committed.ref;
recovered.attempt === committed.attempt;
recovered.snapshot === committed.snapshot;
No new Birth, ancestry frame, parent commit, or child generation is allowed merely because the runner changed.
Keep restart distinct from retry
Restart preserves one incarnation. A child retry does not. After a failed attempt, the parent
commits its ChildRetry cursor and later a ChildResume step before arming a fresh exact
incarnation. The new child has a different generation and Ref and the next attempt number.
Removing a family member and later adding the same key is also a new generation. The key names the member's logical position; generation and attempt distinguish the incarnations that have occupied it. Late outcomes from an older Ref are stale evidence and cannot settle the current child.
| Boundary | Generation / Ref | Attempt | Parent commit |
| --------------------- | ---------------- | ----------- | -------------------------------- |
| Runner restart | preserved | preserved | none |
| Child retry | fresh | incremented | ChildRetry, then ChildResume |
| Remove and re-add key | fresh | starts at 1 | membership-changing step |
Preserve recursive ancestry unchanged
Every recursive child Birth retains its full ownership path: parent, child site, key, generation,
attempt, Ref, and recursive group. Recovery reuses that ancestry byte-for-byte. It neither appends a
frame nor consumes another unit of maximumDepth.
If the stored checkpoint cannot decode under the registered chart, recovery does not guess. The engine records a revalidation incident and Parks the owning root so an operator can choose an explicit migration or disposition.
Test cold recovery, not only hot continuity
- Start one recursive parent and retain its active child's generation, Ref, attempt, and ancestry.
- Persist the parent and child checkpoints, then close the entire runner scope.
- Create a fresh engine over the same storage and register the same charts.
- Acquire the parent through an ordinary read or command and verify the exact child locator is recovered.
- Verify reenactment occurs without another parent commit or distinct child Birth.
- Separately exercise retry and prove it creates a fresh generation, Ref, and attempt.
Next, Component Definitions and Placements returns to reusable authored structure while the remaining Recursive Systems guides develop mutual groups and Resource propagation.