This document describes the current serialized-Python callable payload used by
hierarchical Worker.register for Python callables. The public registration
contract is defined in
callable-identity-registration.md:
registration returns a CallableHandle, task frames carry the handle hash
digest, and integer execution slots remain target-local internals.
Python callable registration uses a small binary envelope followed by the serializer bytes:
SPYC payload:
magic: b"SPYC"
version: uint8 = 1
serializer: uint8 = 1 # CLOUDPICKLE
flags: uint16 = 0
payload_size: uint64
payload: bytes
The payload field is cloudpickle.dumps(target).
Targets validate the envelope before unpickling:
- magic must be
SPYC; - version must be supported;
- serializer must be
CLOUDPICKLE; - flags must be zero;
payload_sizemust fit within the staged bytes.
This feature unpickles code/data produced by the same user process. It is not a security boundary and must not be used for untrusted bytes.
PYTHON_SERIALIZED callable identity is computed from the serialized payload
identity, not from a semantic Python source-code identity:
PYTHON_SERIALIZED descriptor:
descriptor_schema_version
callable_kind = PYTHON_SERIALIZED
payload_format_version
serializer_id
payload_sha256
payload_sha256 is computed over the serializer bytes inside the SPYC
envelope, not over the header itself.
Equivalent Python functions may produce different cloudpickle bytes and therefore different hashids. This is expected: the handle identifies the exact serialized callable payload registered on that Worker.
Before children are started, Python callables are installed into the parent identity registry and inherited by forked children through the startup snapshot.
After children have started, the parent:
- serializes the callable into the
SPYCpayload; - computes the
PYTHON_SERIALIZEDdescriptor and hash digest; - creates an unpublished parent-side registration entry and handle id;
- stages the
SPYCpayload in POSIX shared memory; - broadcasts a Python register control with the staged shm name and digest to Python-capable children.
The parent returns the handle only after every target reports success. If any target fails, the unpublished entry is removed and confirmed installs are cleaned up by digest-owned unregister control.
The child:
- reads the digest from the control frame;
- opens the staged shm payload;
- validates the envelope and recomputes the descriptor digest;
- rejects the request with
HASHID_DESCRIPTOR_MISMATCHif the payload digest does not match the requested digest; - increments the target-local refcount for an existing matching digest, or unpickles and installs the callable into a new private local slot.
Unregister is digest-owned. A child decrements the target-local refcount for the digest and removes the local mapping only when the final reference is released. The parent does not send or reuse child slot numbers.
If post-start register fails after a partial install, the parent sends best-effort digest-owned cleanup. If cleanup cannot be confirmed, that hashid is marked uncertain on the Worker and later attempts to register the same hashid are rejected until the Worker is restarted.
Python callable serialization applies to Python-capable hierarchical children:
- SUB workers for
orch.submit_sub; - next-level Worker child dispatch loops for Python orchestration callables.
It does not populate an inner Worker's own registry for callables that are owned by that inner Worker. Those must be registered on the inner Worker.