Skip to content

Add structural ActorRef boundary - #43

Merged
JovaniPink merged 1 commit into
masterfrom
actor-ref-boundary
Aug 24, 2026
Merged

Add structural ActorRef boundary#43
JovaniPink merged 1 commit into
masterfrom
actor-ref-boundary

Conversation

@JovaniPink

@JovaniPink JovaniPink commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

Separate the consumer-facing actor reference contract from the concrete actor lifecycle while preserving precise types for actors created from known logic.

Rationale

XState v5 and the v6 architecture research distinguish what an actor consumer may do from what the concrete runtime owns. Python benefits from the same boundary through structural protocols: application code can depend on send, snapshot, and subscription capabilities without receiving start, stop, spawn, or backend details.

This is a typing and interface boundary. Runtime actors, mailboxes, invocation reconciliation, and lifecycle behavior remain unchanged.

Scope

  • Add defaulted ActorRef[SendEventT, SnapshotT] as a runtime-checkable structural protocol.
  • Keep Actor.send() returning the current snapshot for backward compatibility.
  • Keep concrete Actor[SendEventT, SnapshotT, OutputT] lifecycle and spawn methods.
  • Widen ActorSystem.get() to ActorRef[Any, Any] | None for heterogeneous lookup.
  • Widen public parent references and child mappings to ActorRef.
  • Type interpreter messaging targets as actor references.
  • Keep create_actor() and spawn() return types as precise concrete actors for known machine, promise, callback, and observable logic.
  • Add structural CompletionSnapshot[OutputT] for completion-capable snapshots.
  • Overload to_promise() for concrete actors and compatible actor references while preserving output inference.
  • Export ActorRef, CompletionSnapshot, and SubscriptionProtocol from xstate.
  • Document lifecycle ownership and consumer-only actor boundaries.

Compatibility

Existing actor construction, start, stop, send, subscribe, get_snapshot, state, spawn, invoke, parent-child ownership, and system registration behavior is unchanged. Raw and unparameterized consumers remain Any compatible. Known logic still returns concrete Actor values, so this PR does not remove lifecycle methods from existing call sites.

Non-scope

  • Remote transports, actor proxies, or location transparency.
  • Durable addresses, incarnation identifiers, or persistence changes.
  • Runtime message or snapshot validation.
  • Actor-system topology inspection.
  • Changes to invocation or mailbox semantics.
  • Version changes or publication.

Validation

Local Python 3.14 on exact head 9072aed:

  • poetry run python -m pytest tests/ --ignore=tests/test_scxml.py: 482 passed.
  • poetry run python -m pytest tests/test_scxml.py: 57 passed.
  • poetry run mypy src/xstate/: passed.
  • poetry run mypy --strict src/xstate/algorithm.py: passed.
  • Positive and negative strict-mypy consumer fixtures: passed.
  • Ruff format and lint checks: passed.
  • poetry check --lock: passed.
  • poetry build: passed.
  • poetry run python scripts/validate_distribution.py: installed-wheel smoke passed.

Hosted exact head 9072aedfe6c9a4003fe6ff4cebfcf13c4d4357bd:

  • Python 3.13 test job: passed.
  • Python 3.14 test job: passed.
  • SCXML smoke job: passed.
  • Python 3.14 code-quality job: passed.

Risks and rollback

The main risk is variance or overload behavior widening too much or rejecting valid structural implementations. Strict-mypy fixtures cover invalid sends and snapshots, concrete actor precision, widened system lookup, and to_promise inference through both concrete actors and actor references. Runtime tests cover structural protocol recognition and completion.

Rollback is a revert of this PR. It changes no persisted data, dependency, runtime effect order, or public lifecycle behavior.

Review focus

  • The minimal capability set on ActorRef.
  • The intentional difference between precise creation and widened heterogeneous lookup.
  • Public versus internal parent and child ownership types.
  • CompletionSnapshot structural compatibility and to_promise inference.
  • Backward compatibility of concrete Actor.send() and lifecycle methods.

Stack and merge order

This is PR 3 of 3. PR 1 and PR 2 have merged, so this PR now targets master and is the final layer in the stack.

@JovaniPink
JovaniPink changed the base branch from bounded-microstep-traces to master August 24, 2026 18:16
@JovaniPink
JovaniPink marked this pull request as ready for review August 24, 2026 18:16
@JovaniPink
JovaniPink merged commit 075a104 into master Aug 24, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant